diff --git a/Generators/DIFGenerator/CMakeLists.txt b/Generators/DIFGenerator/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d644dfec9c65ce8caa810dc203d369c97494b8f3 --- /dev/null +++ b/Generators/DIFGenerator/CMakeLists.txt @@ -0,0 +1,10 @@ +################################################################################ +# Package: DIFGenerator +################################################################################ + +# Declare the package name: +atlas_subdir( DIFGenerator ) + +# Install files from the package: +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) + diff --git a/Generators/DIFGenerator/README.md b/Generators/DIFGenerator/README.md new file mode 100644 index 0000000000000000000000000000000000000000..34dbc557986ed9b4e3f025b787375ace36c69cd3 --- /dev/null +++ b/Generators/DIFGenerator/README.md @@ -0,0 +1,18 @@ +# Decay In Flight Sampler + +The DIFSampler models a two-body decay. + +## Usage + +The `runG4DecayInFlight.py` file shows a default configuration. + +Options available through the `DIFSampler` constructor include: + +* daughter1_pid - The pid of the first decay particle. The default valid pids are listed [here](https://gitlab.cern.ch/atlas/athena/-/blob/master/Generators/ParticleGun/python/samplers.py#L825). (default: 11) +* daughter2_pid - The pid of the second decay particle. The default valid pids are listed [here](https://gitlab.cern.ch/atlas/athena/-/blob/master/Generators/ParticleGun/python/samplers.py#L825). (default: -11) +* mother_pid - The pid of the mother particle. Only set this if you need to get the mother's pid from the mother_sampler property (default: None) +* mother_mom - A momentum sampler representing the mother particle's momentum. (default: PG.EThetaMPhiSampler(sqrt((1 * TeV)**2 + (10 * MeV)**2),0,10*MeV,0)) +* mother_pos - A position sampler representing the mother particle's position. (default: PG.PosSampler(0,0,[-1500,0],0)) + +The pid, momentum sampler, and position sampler of the mother particle can be modified after initialization by setting the `mother_sampler` property of the `DIFSampler`. The `mother_sampler` property should be a [ParticleSampler](https://gitlab.cern.ch/atlas/athena/-/blob/master/Generators/ParticleGun/python/samplers.py#L858). + diff --git a/Generators/DIFGenerator/python/DIFSampler.py b/Generators/DIFGenerator/python/DIFSampler.py new file mode 100644 index 0000000000000000000000000000000000000000..835d0f1ec82c849799e62b74cdd57020773be0e6 --- /dev/null +++ b/Generators/DIFGenerator/python/DIFSampler.py @@ -0,0 +1,363 @@ +#!/usr/bin/env python + +#TODO: exponential decay lifetime? + +import ParticleGun as PG +from math import sqrt, sin, cos, acos +from random import uniform +from AthenaCommon.SystemOfUnits import TeV, MeV +from AthenaCommon.PhysicalConstants import pi + +class DIFSampler(PG.ParticleSampler): + """ + A particle gun which models 2 particle decay. + """ + class particle: + """ + A helper class to hold information about a particle. + """ + def __init__(self,pid = None,mass = None,mom=None,theta=None,phi=None,pos=None): + self.pid = pid + if mass is None: + self.mass = PG.MASSES[abs(pid)] + else: + self.mass = mass + + self.mom_mag = mom + self.theta = theta + self.phi = phi + self.pos = pos + + if self.mass is not None and self.mom_mag is not None: + self.E = sqrt(self.mom_mag**2 + self.mass**2) + else: + self.E = None + + if self.theta is not None and self.phi is not None and self.mass is not None and self.E is not None: + self.mom = PG.EThetaMPhiSampler(self.E,self.theta,self.mass,self.phi).shoot() + else: + self.mom = None + + def __init__(self, daughter1_pid = 11, daughter2_pid = -11, mother_pid = None, mother_mom = PG.EThetaMPhiSampler(sqrt((1*TeV)**2 + (10*MeV)**2),0,10*MeV,0),mother_pos = PG.PosSampler(0,0,[-1500,0],0)): + self._mother_sampler = PG.ParticleSampler(mother_pid,mother_mom,mother_pos) + + self.daughter1 = self.particle(daughter1_pid) + self.daughter2 = self.particle(daughter2_pid) + + @property + def mother_sampler(self): + return self._mother_sampler + + @mother_sampler.setter + def mother_sampler(self,sampler): + if isinstance(sampler,PG.ParticleSampler) or issubclass(type(sampler),PG.ParticleSampler): + self._mother_sampler = sampler + else: + raise AttributeError("DIFSampler: Trying to set mother_sampler to something other than a ParticleSampler.") + + def calculate_decay_p(self,m0,m1,m2): + return sqrt(m0**4 - (2*m0**2 * m1**2) + (m1**4) - (2*m0**2 * m2**2) - (2*m1**2 *m2**2) + (m2**4)) / (2*m0) + + def lorentz_transformation(self): + self.mother_mom = self.mother.mom.shoot() + Bx = self.mother_mom.Px() / self.mother_mom.E() + By = self.mother_mom.Py() / self.mother_mom.E() + Bz = self.mother_mom.Pz() / self.mother_mom.E() + self.daughter1.mom.Boost(Bx,By,Bz) + self.daughter2.mom.Boost(Bx,By,Bz) + + def shoot(self): + "Mother particle decays into two daughter particles" + ## Shoot daughter 1 in a random direction in CM frame + self.daughter1.phi = uniform(0,2 * pi) + + ## ensure cos(theta) is uniform from -1 to 1 + cos_theta = uniform(-1,1) + self.daughter1.theta = acos(cos_theta) + + self.daughter2.phi = self.daughter1.phi + pi + self.daughter2.theta = acos(-cos_theta) + + ## The magnitude of the momentum will be equal and opposite + self.mother = self.mother_sampler + p = self.calculate_decay_p(self.mother.mom.mass(),self.daughter1.mass,self.daughter2.mass) + + self.daughter1.E = sqrt(self.daughter1.mass**2 + p**2) + self.daughter2.E = sqrt(self.daughter2.mass**2 + p**2) + + self.daughter1.mom = PG.EThetaMPhiSampler(self.daughter1.E,self.daughter1.theta,self.daughter1.mass,self.daughter1.phi).shoot() + self.daughter2.mom = PG.EThetaMPhiSampler(self.daughter2.E,self.daughter2.theta,self.daughter2.mass,self.daughter2.phi).shoot() + + ## boost into lab frame + self.lorentz_transformation() + + self.mother_pos = self.mother.pos.shoot() + d1 = PG.SampledParticle(self.daughter1.pid,self.daughter1.mom,self.mother_pos) + d2 = PG.SampledParticle(self.daughter2.pid,self.daughter2.mom,self.mother_pos) + + return [d1,d2] + +if __name__ == "__main__": + import matplotlib.pyplot as plt + import sys + + show_graphs = False + if len(sys.argv) > 1 and sys.argv[1] == "-g": + show_graphs = True + + epsilon = 10**-6 #account for round off error + + ## test motionless mother particle + mother_pid = 321 #K+ + mother_mass = PG.MASSES[mother_pid] + daughter0_pid = 211 #pi+ + daughter1_pid = 111 #pi0 + + ## check uniformifty of angles + if show_graphs: + cos_thetas = [[],[]] + thetas = [[],[]] + phis = [[],[]] + + n = 100 + for i in range(n): + try: + DIFS = DIFSampler(daughter0_pid,daughter1_pid, mother_pid) # K+ -> pi+ and pi0 + DIFS.mother_sampler.mom = PG.EThetaMPhiSampler(mother_mass,0,mother_mass,0) + daughters = DIFS.shoot() + + mother_mom = DIFS.mother_sampler.mom.shoot() + + assert daughters[0].mom.E() + daughters[1].mom.E() == mother_mass + assert (daughters[0].mom.E() + daughters[1].mom.E())**2 - (daughters[0].mom.P() - daughters[1].mom.P())**2 == (PG.MASSES[mother_pid])**2 + assert abs(daughters[0].mom.P() - daughters[1].mom.P()) <= epsilon + assert daughters[0].mom.Theta() - epsilon <= abs(pi - daughters[1].mom.Theta()) <= daughters[0].mom.Theta() + epsilon + assert abs(daughters[0].mom.Px() + daughters[1].mom.Px()) <= epsilon + assert abs(daughters[0].mom.Py() + daughters[1].mom.Py()) <= epsilon + assert abs(daughters[0].mom.Pz() + daughters[1].mom.Pz()) <= epsilon + assert daughters[0].pos.X() == daughters[1].pos.X() == DIFS.mother_pos.X() + assert daughters[0].pos.Y() == daughters[1].pos.Y() == DIFS.mother_pos.Y() + assert daughters[0].pos.Z() == daughters[1].pos.Z() == DIFS.mother_pos.Z() + + if show_graphs: + cos_thetas[0].append(cos(daughters[0].mom.Theta())) + cos_thetas[1].append(cos(daughters[1].mom.Theta())) + thetas[0].append(daughters[0].mom.Theta()) + thetas[1].append(daughters[1].mom.Theta()) + phis[0].append(daughters[0].mom.Phi()) + phis[1].append(daughters[1].mom.Phi()) + + except AssertionError: + print("Error on run " + str(i)) + + print("mother particle:") + print(" E = " + str(mother_mom.E())) + print(" M = " + str(mother_mom.M())) + print(" P = " + str(mother_mom.P())) + print(" Px = " + str(mother_mom.Px())) + print(" Py = " + str(mother_mom.Py())) + print(" Pz = " + str(mother_mom.Pz())) + print(" theta = " + str(mother_mom.Theta())) + print(" phi = " + str(mother_mom.Phi())) + print(" x = " + str(DIFS.mother_pos.X())) + print(" y = " + str(DIFS.mother_pos.Y())) + print(" z = " + str(DIFS.mother_pos.Z())) + + print("daughter 0 particle:") + print(" E = " + str(daughters[0].mom.E())) + print(" M = " + str(daughters[0].mom.M())) + print(" P = " + str(daughters[0].mom.P())) + print(" Px = " + str(daughters[0].mom.Px())) + print(" Py = " + str(daughters[0].mom.Py())) + print(" Pz = " + str(daughters[0].mom.Pz())) + print(" theta = " + str(daughters[0].mom.Theta())) + print(" phi = " + str(daughters[0].mom.Phi())) + print(" x = " + str(daughters[0].pos.X())) + print(" y = " + str(daughters[0].pos.Y())) + print(" z = " + str(daughters[0].pos.Z())) + + print("daughter 1 particle:") + print(" E = " + str(daughters[1].mom.E())) + print(" M = " + str(daughters[1].mom.M())) + print(" P = " + str(daughters[1].mom.P())) + print(" Px = " + str(daughters[1].mom.Px())) + print(" Py = " + str(daughters[1].mom.Py())) + print(" Pz = " + str(daughters[1].mom.Pz())) + print(" theta = " + str(daughters[1].mom.Theta())) + print(" phi = " + str(daughters[1].mom.Phi())) + print(" x = " + str(daughters[1].pos.X())) + print(" y = " + str(daughters[1].pos.Y())) + print(" z = " + str(daughters[1].pos.Z())) + + raise + + if show_graphs: + fig,axs = plt.subplots(2,3) + axs[0,0].hist(thetas[0]) + axs[0,0].set_title("daughter 0: theta") + axs[0,1].hist(cos_thetas[1]) + axs[0,1].set_title("daughter 0: cos(theta)") + axs[0,2].hist(phis[1]) + axs[0,2].set_title("daughter 0: phi") + axs[1,0].hist(thetas[1]) + axs[1,0].set_title("daughter 1: theta") + axs[1,1].hist(cos_thetas[0]) + axs[1,1].set_title("daughter 1, cos(theta)") + axs[1,2].hist(phis[0]) + axs[1,2].set_title("daughter 1, phi") + plt.show() + + # test moving mother particle + mother_pid = 15 #tau + daughter0_pid = 16 #nu_tau + daughter1_pid = 211 #pi+- + + n = 100 + for i in range(n): + M = PG.MASSES[mother_pid] + theta = acos(uniform(-1,1)) + mother_mom = PG.EThetaMPhiSampler([M,3*M],theta,M,[0,2*pi]) + mother_pos = PG.PosSampler(x=0,y=0,z=[-1500,0],t=0) + + DIFS = DIFSampler(daughter0_pid,daughter1_pid,mother_pid) # tau -> nu_tau and pi+- + DIFS.mother_sampler = PG.ParticleSampler(pid=mother_pid,mom=mother_mom,n=1,pos=mother_pos) + daughters = DIFS.shoot() + + try: + mother_mom = DIFS.mother_mom + s = daughters[0].mom+daughters[1].mom + + assert mother_mom.E() - epsilon <= s.E() <= mother_mom.E() + epsilon + assert mother_mom.P() - epsilon <= s.P()<= mother_mom.P() + epsilon + assert mother_mom.Px() - epsilon <= s.Px() <= mother_mom.Px() + epsilon + assert mother_mom.Py() - epsilon <= s.Py() <= mother_mom.Py() + epsilon + assert mother_mom.Pz() - epsilon <= s.Pz() <= mother_mom.Pz() + epsilon + assert daughters[0].pos.X() == daughters[1].pos.X() == DIFS.mother_pos.X() + assert daughters[0].pos.Y() == daughters[1].pos.Y() == DIFS.mother_pos.Y() + assert daughters[0].pos.Z() == daughters[1].pos.Z() == DIFS.mother_pos.Z() + + except AssertionError: + print("Error on run " + str(i)) + + print("mother particle:") + print(" E = " + str(mother_mom.E())) + print(" M = " + str(mother_mom.M())) + print(" P = " + str(mother_mom.P())) + print(" Px = " + str(mother_mom.Px())) + print(" Py = " + str(mother_mom.Py())) + print(" Pz = " + str(mother_mom.Pz())) + print(" theta = " + str(mother_mom.Theta())) + print(" phi = " + str(mother_mom.Phi())) + print(" x = " + str(DIFS.mother_pos.X())) + print(" y = " + str(DIFS.mother_pos.Y())) + print(" z = " + str(DIFS.mother_pos.Z())) + + print("daughter 0 particle:") + print(" E = " + str(daughters[0].mom.E())) + print(" M = " + str(daughters[0].mom.M())) + print(" P = " + str(daughters[0].mom.P())) + print(" Px = " + str(daughters[0].mom.Px())) + print(" Py = " + str(daughters[0].mom.Py())) + print(" Pz = " + str(daughters[0].mom.Pz())) + print(" theta = " + str(daughters[0].mom.Theta())) + print(" phi = " + str(daughters[0].mom.Phi())) + print(" x = " + str(daughters[0].pos.X())) + print(" y = " + str(daughters[0].pos.Y())) + print(" z = " + str(daughters[0].pos.Z())) + + print("daughter 1 particle:") + print(" E = " + str(daughters[1].mom.E())) + print(" M = " + str(daughters[1].mom.M())) + print(" P = " + str(daughters[1].mom.P())) + print(" Px = " + str(daughters[1].mom.Px())) + print(" Py = " + str(daughters[1].mom.Py())) + print(" Pz = " + str(daughters[1].mom.Pz())) + print(" theta = " + str(daughters[1].mom.Theta())) + print(" phi = " + str(daughters[1].mom.Phi())) + print(" x = " + str(daughters[1].pos.X())) + print(" y = " + str(daughters[1].pos.Y())) + print(" z = " + str(daughters[1].pos.Z())) + + raise + + # Test default arguments + epsilon = 2 # increase round off error because the numbers are much larger + + n = 100 + for i in range(n): + DIFS = DIFSampler() + daughters = DIFS.shoot() + + mother_mom = DIFS.mother_mom + s = daughters[0].mom+daughters[1].mom + + try: + assert DIFS.mother_sampler.pid() == None + assert mother_mom.E()**2 - mother_mom.P()**2 - epsilon <= s.E()**2 - s.P()**2 <= mother_mom.E()**2 - mother_mom.P()**2 + epsilon + assert mother_mom.Px() - epsilon <= s.Px() <= mother_mom.Px() + epsilon + assert mother_mom.Py() - epsilon <= s.Py() <= mother_mom.Py() + epsilon + assert mother_mom.Pz() - epsilon <= s.Pz() <= mother_mom.Pz() + epsilon + assert daughters[0].pos.X() == daughters[1].pos.X() == DIFS.mother_pos.X() + assert daughters[0].pos.Y() == daughters[1].pos.Y() == DIFS.mother_pos.Y() + assert daughters[0].pos.Z() == daughters[1].pos.Z() == DIFS.mother_pos.Z() + + except AssertionError: + print("Error on run " + str(i)) + + print("mother particle:") + print(" E = " + str(mother_mom.E())) + print(" M = " + str(mother_mom.M())) + print(" P = " + str(mother_mom.P())) + print(" Px = " + str(mother_mom.Px())) + print(" Py = " + str(mother_mom.Py())) + print(" Pz = " + str(mother_mom.Pz())) + print(" theta = " + str(mother_mom.Theta())) + print(" phi = " + str(mother_mom.Phi())) + print(" x = " + str(DIFS.mother_pos.X())) + print(" y = " + str(DIFS.mother_pos.Y())) + print(" z = " + str(DIFS.mother_pos.Z())) + + print("daughter 0 particle:") + print(" E = " + str(daughters[0].mom.E())) + print(" M = " + str(daughters[0].mom.M())) + print(" P = " + str(daughters[0].mom.P())) + print(" Px = " + str(daughters[0].mom.Px())) + print(" Py = " + str(daughters[0].mom.Py())) + print(" Pz = " + str(daughters[0].mom.Pz())) + print(" theta = " + str(daughters[0].mom.Theta())) + print(" phi = " + str(daughters[0].mom.Phi())) + print(" x = " + str(daughters[0].pos.X())) + print(" y = " + str(daughters[0].pos.Y())) + print(" z = " + str(daughters[0].pos.Z())) + + print("daughter 1 particle:") + print(" E = " + str(daughters[1].mom.E())) + print(" M = " + str(daughters[1].mom.M())) + print(" P = " + str(daughters[1].mom.P())) + print(" Px = " + str(daughters[1].mom.Px())) + print(" Py = " + str(daughters[1].mom.Py())) + print(" Pz = " + str(daughters[1].mom.Pz())) + print(" theta = " + str(daughters[1].mom.Theta())) + print(" phi = " + str(daughters[1].mom.Phi())) + print(" x = " + str(daughters[1].pos.X())) + print(" y = " + str(daughters[1].pos.Y())) + print(" z = " + str(daughters[1].pos.Z())) + + raise + + # pass invalid type to mother_sampler + try: + DIFS = DIFSampler() + DIFS.mother_sampler = PG.SampledParticle() + raise AssertionError("mother_sampler set to improper type") + except AttributeError: + pass + + # pass derived type to mother_sampler + class SP(PG.ParticleSampler): + pass + + DIFS = DIFSampler() + DIFS.mother_sampler = SP() + + print("DIFSampler: All unit tests passed") \ No newline at end of file diff --git a/Generators/DIFGenerator/python/__init__.py b/Generators/DIFGenerator/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f93ebea78528397b5a0c901aacc6c2d7ff6771a6 --- /dev/null +++ b/Generators/DIFGenerator/python/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2021 CERN for the benefit of the FASER collaboration + +from DIFGenerator.DIFSampler import DIFSampler \ No newline at end of file diff --git a/Simulation/G4Faser/G4FaserAlg/test/runG4DecayInFlight.py b/Simulation/G4Faser/G4FaserAlg/test/runG4DecayInFlight.py new file mode 100644 index 0000000000000000000000000000000000000000..88401cafb3bbc781cec50291656b824931e5953e --- /dev/null +++ b/Simulation/G4Faser/G4FaserAlg/test/runG4DecayInFlight.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python +if __name__ == "__main__": + import os + import sys + import GaudiPython + import ParticleGun as PG + from DIFGenerator import DIFSampler + from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + from AthenaConfiguration.ComponentFactory import CompFactory + from AthenaCommon.AppMgr import * + from AthenaCommon.Logging import log, logging + from AthenaCommon.SystemOfUnits import TeV + from AthenaCommon.PhysicalConstants import pi + from AthenaCommon.Constants import VERBOSE, INFO + from AthenaCommon.Configurable import Configurable + from CalypsoConfiguration.AllConfigFlags import ConfigFlags + from CalypsoConfiguration.MainServicesConfig import MainServicesCfg + from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg + from McEventSelector.McEventSelectorConfig import McEventSelectorCfg + from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg + from G4FaserAlg.G4FaserAlgConfigNew import G4FaserAlgCfg + from G4FaserServices.G4FaserServicesConfigNew import G4GeometryNotifierSvcCfg +# +# Set up logging and new style config +# + log.setLevel(VERBOSE) + Configurable.configurableRun3Behavior = True +# +# Input settings (Generator file) +# +# from AthenaConfiguration.TestDefaults import defaultTestFiles +# ConfigFlags.Input.Files = defaultTestFiles.EVNT +# +# Alternatively, these must ALL be explicitly set to run without an input file +# (if missing, it will try to read metadata from a non-existent file and crash) +# + ConfigFlags.Input.Files = [""] + ConfigFlags.Input.isMC = True + ConfigFlags.Input.RunNumber = 12345 + ConfigFlags.Input.Collections = [""] + ConfigFlags.Input.ProjectName = "mc19" + ConfigFlags.Common.isOnline = False + ConfigFlags.Beam.Type = "collisions" + ConfigFlags.Beam.Energy = 7*TeV # Informational, does not affect simulation + ConfigFlags.GeoModel.FaserVersion = "FASER-01" # Always needed + ConfigFlags.IOVDb.GlobalTag = "OFLCOND-XXXX-XXX-XX" # Always needed; only the OFLCOND part matters +# Workaround for bug/missing flag; unimportant otherwise + ConfigFlags.addFlag("Input.InitialTimeStamp", 0) +# Workaround to avoid problematic ISF code + ConfigFlags.GeoModel.Layout = "Development" +# +# Output settings +# + ConfigFlags.Output.HITSFileName = "DecayInFlight.HITS.pool.root" + ConfigFlags.GeoModel.GeoExportFile = "faserGeo.db" # Optional dump of geometry for browsing in vp1light +# +# Geometry-related settings +# Do not change! +# + ConfigFlags.Detector.SimulateVeto = True + ConfigFlags.Detector.GeometryVeto = True + ConfigFlags.Detector.SimulateTrigger= True + ConfigFlags.Detector.GeometryTrigger= True + ConfigFlags.Detector.SimulatePreshower = True + ConfigFlags.Detector.GeometryPreshower = True + ConfigFlags.Detector.SimulateFaserSCT = True + ConfigFlags.Detector.GeometryFaserSCT = True + ConfigFlags.Detector.SimulateUpstreamDipole = True + ConfigFlags.Detector.SimulateCentralDipole = True + ConfigFlags.Detector.SimulateDownstreamDipole = True + ConfigFlags.Detector.GeometryUpstreamDipole = True + ConfigFlags.Detector.GeometryCentralDipole = True + ConfigFlags.Detector.GeometryDownstreamDipole = True + ConfigFlags.GeoModel.Align.Dynamic = False + ConfigFlags.Sim.ReleaseGeoModel = False +# +# All flags should be set before calling lock +# + ConfigFlags.lock() +# +# Construct ComponentAccumulator +# + acc = MainServicesCfg(ConfigFlags) +# +# Particle Gun generator (comment out to read generator file) +# Raw energies (without units given) are interpreted as MeV +# + pg = PG.ParticleGun() + pg.McEventKey = "GEN_EVENT" + pg.randomSeed = 123456 + + pg.sampler = DIFSampler() + acc.addEventAlgo(pg, "AthBeginSeq") # to run *before* G4 +# +# Only one of these two should be used in a given job +# (MCEventSelectorCfg for generating events with no input file, +# PoolReadCfg when reading generator data from an input file) +# + acc.merge(McEventSelectorCfg(ConfigFlags)) + # acc.merge(PoolReadCfg(ConfigFlags)) +# +# Output stream configuration +# + acc.merge(OutputStreamCfg(ConfigFlags, + "HITS", + ["EventInfo#*", + "McEventCollection#TruthEvent", + "McEventCollection#GEN_EVENT", + "ScintHitCollection#*", + "FaserSiHitCollection#*" + ], disableEventTag=True)) + acc.getEventAlgo("OutputStreamHITS").AcceptAlgs = ["G4FaserAlg"] # optional + acc.getEventAlgo("OutputStreamHITS").WritingTool.ProcessingTag = "StreamHITS" # required +# +# Here is the configuration of the Geant4 pieces +# + acc.merge(FaserGeometryCfg(ConfigFlags)) + acc.merge(G4FaserAlgCfg(ConfigFlags)) + acc.addService(G4GeometryNotifierSvcCfg(ConfigFlags, ActivateLVNotifier=True)) +# +# Verbosity +# +# ConfigFlags.dump() +# logging.getLogger('forcomps').setLevel(VERBOSE) +# acc.foreach_component("*").OutputLevel = VERBOSE +# acc.foreach_component("*ClassID*").OutputLevel = INFO +# acc.getService("StoreGateSvc").Dump=True +# acc.getService("ConditionStore").Dump=True +# acc.printConfig() + f=open('FaserG4AppCfg_EVNT.pkl','wb') + acc.store(f) + f.close() +# +# Execute and finish +# + sys.exit(int(acc.run(maxEvents=500).isFailure()))