From c75b0b61b9e4cdb027b6494b99984c842b42914f Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Thu, 25 Jan 2024 15:52:53 -0600 Subject: [PATCH 01/20] feat: add Geant4TestStackAction --- DDG4/include/DDG4/Geant4TestActions.h | 20 ++++++++++++++++++++ DDG4/plugins/Geant4Factories.cpp | 2 +- DDG4/src/Geant4TestActions.cpp | 27 +++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/DDG4/include/DDG4/Geant4TestActions.h b/DDG4/include/DDG4/Geant4TestActions.h index 9320e4abc..06b3e67fe 100644 --- a/DDG4/include/DDG4/Geant4TestActions.h +++ b/DDG4/include/DDG4/Geant4TestActions.h @@ -148,6 +148,26 @@ namespace dd4hep { void operator()(const G4Step*, G4SteppingManager*) override; }; + /// Example stacking action doing nothing, but print + /** + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4TestStackAction: public Geant4StackingAction, public Geant4TestBase { + public: + /// Standard constructor with initializing arguments + Geant4TestStackAction(Geant4Context* c, const std::string& n); + /// Default destructor + virtual ~Geant4TestStackAction(); + /// New-stage callback + virtual void newStage(G4StackManager*) override; + /// Preparation callback + virtual void prepare(G4StackManager*) override; + /// Return TrackClassification with enum G4ClassificationOfNewTrack or NoTrackClassification + virtual TrackClassification classifyNewTrack(G4StackManager*, const G4Track*) override; + }; + /// Example sensitve detector action doing nothing, but print /** * \author M.Frank diff --git a/DDG4/plugins/Geant4Factories.cpp b/DDG4/plugins/Geant4Factories.cpp index a0a95ce7a..19aec6761 100644 --- a/DDG4/plugins/Geant4Factories.cpp +++ b/DDG4/plugins/Geant4Factories.cpp @@ -139,7 +139,7 @@ DECLARE_GEANT4ACTION(Geant4TestRunAction) DECLARE_GEANT4ACTION(Geant4TestEventAction) DECLARE_GEANT4ACTION(Geant4TestStepAction) DECLARE_GEANT4ACTION(Geant4TestTrackAction) -//DECLARE_GEANT4ACTION(Geant4TestStackingAction) +DECLARE_GEANT4ACTION(Geant4TestStackAction) DECLARE_GEANT4ACTION(Geant4TestGeneratorAction) DECLARE_GEANT4SENSITIVE(Geant4TestSensitive) DECLARE_GEANT4SENSITIVE(Geant4TestSensitiveTracker) diff --git a/DDG4/src/Geant4TestActions.cpp b/DDG4/src/Geant4TestActions.cpp index c752033de..192b0f4b6 100644 --- a/DDG4/src/Geant4TestActions.cpp +++ b/DDG4/src/Geant4TestActions.cpp @@ -185,6 +185,33 @@ void Geant4TestStepAction::operator()(const G4Step*, G4SteppingManager*) { PRINT("%s> calling operator()", m_type.c_str()); } +/// Standard constructor with initializing arguments +Geant4TestStackAction::Geant4TestStackAction(Geant4Context* c, const std::string& n) + : Geant4StackingAction(c, n), Geant4TestBase(this, "Geant4TestStackAction") { + InstanceCount::increment(this); +} + +/// Default destructor +Geant4TestStackAction::~Geant4TestStackAction() { + InstanceCount::decrement(this); +} +/// New-stage callback +void Geant4TestStackAction::newStage(G4StackManager*) { + PRINT("%s> calling newStage()", m_type.c_str()); +} +/// Preparation callback +void Geant4TestStackAction::prepare(G4StackManager*) { + PRINT("%s> calling prepare()", m_type.c_str()); +} +/// Return TrackClassification with enum G4ClassificationOfNewTrack or NoTrackClassification +TrackClassification Geant4TestStackAction::classifyNewTrack(G4StackManager*, const G4Track* trk) { + PRINT("%s> calling classifyNewTrack(track=%d, parent=%d, position=(%f,%f,%f) Context: run=%p evt=%p)", + m_type.c_str(), trk->GetTrackID(), + trk->GetParentID(), trk->GetPosition().x(), trk->GetPosition().y(), trk->GetPosition().z(), + &context()->run(), &context()->event()); + return TrackClassification(); +} + /// Standard constructor with initializing arguments Geant4TestSensitive::Geant4TestSensitive(Geant4Context* c, const std::string& n, DetElement det, Detector& description) : Geant4Sensitive(c, n, det, description), Geant4TestBase(this, "Geant4TestSensitive") { From b68eda529383b60164711c4ebc722aefb4c04d27 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Thu, 25 Jan 2024 15:53:52 -0600 Subject: [PATCH 02/20] feat: allow ddsim --action.step etc for action plugins --- DDG4/python/DDSim/DD4hepSimulation.py | 18 ++++++++ DDG4/python/DDSim/Helper/Action.py | 64 ++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/DDG4/python/DDSim/DD4hepSimulation.py b/DDG4/python/DDSim/DD4hepSimulation.py index ddc7b93a5..5a2760ada 100644 --- a/DDG4/python/DDSim/DD4hepSimulation.py +++ b/DDG4/python/DDSim/DD4hepSimulation.py @@ -347,6 +347,24 @@ def run(self): # configure geometry creation self.geometry.constructGeometry(kernel, geant4, self.output.geometry) + # ---------------------------------------------------------------------------------- + # Configure run, event, track, step actions, if present + for action_name in self.action.run: + action = DDG4.RunAction(kernel, action_name) + kernel.runAction().add(action) + for action_name in self.action.event: + action = DDG4.EventAction(kernel, action_name) + kernel.eventAction().add(action) + for action_name in self.action.track: + action = DDG4.TrackingAction(kernel, action_name) + kernel.trackingAction().add(action) + for action_name in self.action.step: + action = DDG4.SteppingAction(kernel, action_name) + kernel.steppingAction().add(action) + for action_name in self.action.stack: + action = DDG4.StackingAction(kernel, action_name) + kernel.stackingAction().add(action) + # ---------------------------------------------------------------------------------- # Configure Run actions run1 = DDG4.RunAction(kernel, 'Geant4TestRunAction/RunInit') diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index b84c3f70d..b6174070b 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -5,9 +5,9 @@ class Action(ConfigHelper): - """Helper holding sensitive detector actions. + """Helper holding sensitive detector and other actions. - The default tracker and calorimeter actions can be set with + The default tracker and calorimeter sensitive actions can be set with >>> SIM = DD4hepSimulation() >>> SIM.action.tracker=('Geant4TrackerWeightedAction', {'HitPositionCombination': 2, 'CollectSingleDeposits': False}) @@ -30,6 +30,15 @@ class Action(ConfigHelper): >>> SIM = DD4hepSimulation() >>> SIM.action.mapActions['ecal'] =( "CaloPreShowerSDAction", {"FirstLayerNumber": 1} ) + Additional actions can be set as well with + + >>> SIM = DD4hepSimulation() + >>> SIM.action.run = "Geant4TestRunAction" + >>> SIM.action.event = "Geant4TestEventAction" + >>> SIM.action.track = "Geant4TestTrackAction" + >>> SIM.action.step = "Geant4TestStepAction" + >>> SIM.action.stack = "Geant4TestStackAction" + """ def __init__(self): @@ -39,6 +48,11 @@ def __init__(self): self._mapActions = dict() self._trackerSDTypes = ['tracker'] self._calorimeterSDTypes = ['calorimeter'] + self._run = [] + self._event = [] + self._track = [] + self._step = [] + self._stack = [] self._closeProperties() @property @@ -108,3 +122,49 @@ def calorimeterSDTypes(self): @calorimeterSDTypes.setter def calorimeterSDTypes(self, val): self._calorimeterSDTypes = ConfigHelper.makeList(val) + + @property + def run(self): + """ set the default run action """ + return self._run + + @run.setter + def run(self, val): + self._run = ConfigHelper.makeList(val) + + @property + def event(self): + """ set the default event action """ + return self._event + + @event.setter + def event(self, val): + self._event = ConfigHelper.makeList(val) + + @property + def track(self): + """ set the default track action """ + return self._track + + @track.setter + def track(self, val): + self._track = ConfigHelper.makeList(val) + + @property + def step(self): + """ set the default step action """ + return self._step + + @step.setter + def step(self, val): + self._step = ConfigHelper.makeList(val) + + @property + def stack(self): + """ set the default stack action """ + return self._stack + + @stack.setter + def stack(self, val): + self._stack = ConfigHelper.makeList(val) + From f853680bd679d70fdb29f72640fa90bf1d919dac Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Thu, 25 Jan 2024 16:40:04 -0600 Subject: [PATCH 03/20] fix: rm EOF empty line --- DDG4/python/DDSim/Helper/Action.py | 1 - 1 file changed, 1 deletion(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index b6174070b..f4e572351 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -167,4 +167,3 @@ def stack(self): @stack.setter def stack(self, val): self._stack = ConfigHelper.makeList(val) - From 34659bc59e6762fb5f649ad3b31b270d5864e670 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sat, 3 Feb 2024 17:27:50 -0600 Subject: [PATCH 04/20] feat: print Geant4TestActions properties at destruction --- DDG4/src/Geant4TestActions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/DDG4/src/Geant4TestActions.cpp b/DDG4/src/Geant4TestActions.cpp index 192b0f4b6..e5f06689c 100644 --- a/DDG4/src/Geant4TestActions.cpp +++ b/DDG4/src/Geant4TestActions.cpp @@ -49,6 +49,7 @@ Geant4TestBase::Geant4TestBase(Geant4Action* a, const std::string& typ) } /// Default destructor Geant4TestBase::~Geant4TestBase() { + printout(VERBOSE, m_type, "properties at destruction: %d, %f, %s", m_value1, m_value2, m_value3.c_str()); InstanceCount::decrement(this); } From 347d966d6cf8db5ce381ec0d80ea400b124293d0 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sat, 3 Feb 2024 19:50:16 -0600 Subject: [PATCH 05/20] fix: expect list of tuple or dict for actions; parse JSON on CLI --- DDG4/python/DDSim/DD4hepSimulation.py | 28 ++++++++--------- DDG4/python/DDSim/Helper/Action.py | 44 +++++++++++++++++++++------ 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/DDG4/python/DDSim/DD4hepSimulation.py b/DDG4/python/DDSim/DD4hepSimulation.py index 5a2760ada..0917f7790 100644 --- a/DDG4/python/DDSim/DD4hepSimulation.py +++ b/DDG4/python/DDSim/DD4hepSimulation.py @@ -348,22 +348,18 @@ def run(self): self.geometry.constructGeometry(kernel, geant4, self.output.geometry) # ---------------------------------------------------------------------------------- - # Configure run, event, track, step actions, if present - for action_name in self.action.run: - action = DDG4.RunAction(kernel, action_name) - kernel.runAction().add(action) - for action_name in self.action.event: - action = DDG4.EventAction(kernel, action_name) - kernel.eventAction().add(action) - for action_name in self.action.track: - action = DDG4.TrackingAction(kernel, action_name) - kernel.trackingAction().add(action) - for action_name in self.action.step: - action = DDG4.SteppingAction(kernel, action_name) - kernel.steppingAction().add(action) - for action_name in self.action.stack: - action = DDG4.StackingAction(kernel, action_name) - kernel.stackingAction().add(action) + # Configure run, event, track, step, and stack actions, if present + for action_list, DDG4_Action, kernel_Action in \ + [(self.action.run, DDG4.RunAction, kernel.runAction), + (self.action.event, DDG4.EventAction, kernel.eventAction), + (self.action.track, DDG4.TrackingAction, kernel.trackingAction), + (self.action.step, DDG4.SteppingAction, kernel.steppingAction), + (self.action.stack, DDG4.StackingAction, kernel.stackingAction)]: + for action_dict in action_list: + action = DDG4_Action(kernel, action_dict["name"]) + for parameter, value in action_dict['parameter'].items(): + setattr(action, parameter, value) + kernel_Action().add(action) # ---------------------------------------------------------------------------------- # Configure Run actions diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index f4e572351..dc7dbf34f 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -33,11 +33,11 @@ class Action(ConfigHelper): Additional actions can be set as well with >>> SIM = DD4hepSimulation() - >>> SIM.action.run = "Geant4TestRunAction" - >>> SIM.action.event = "Geant4TestEventAction" - >>> SIM.action.track = "Geant4TestTrackAction" - >>> SIM.action.step = "Geant4TestStepAction" - >>> SIM.action.stack = "Geant4TestStackAction" + >>> SIM.action.run = [ ("Geant4TestRunAction", {"Property_int": 10} ) ] + >>> SIM.action.event = [ ("Geant4TestEventAction", {"Property_int": 10} ) ] + >>> SIM.action.track = [ ("Geant4TestTrackAction", {"Property_int": 10} ) ] + >>> SIM.action.step = [ ("Geant4TestStepAction", {"Property_int": 10} ) ] + >>> SIM.action.stack = [ ("Geant4TestStackAction", {"Property_int": 10} ) ] """ @@ -123,6 +123,30 @@ def calorimeterSDTypes(self): def calorimeterSDTypes(self, val): self._calorimeterSDTypes = ConfigHelper.makeList(val) + + @staticmethod + def makeListOfDictFromJSON(val): + if isinstance(val, str): + # assumes: valid JSON string or comma-separated list of names + import json + try: + val = json.loads(val) + except: + val = tuple(val.split(",")) + if isinstance(val, tuple): + # assumes: ( "Geant4TestEventAction", {"Property_int": 10} ) + # creates: { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } + # note: not able to specified as json which only allows a list + val = dict(name=val[0], parameter=val[1]) + if isinstance(val, dict): + # assumes: { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } + # creates: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] + val = [ val ] + if isinstance(val, list): + # assumes: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] + return val + raise RuntimeError("Commandline setting of action is not successful for: %s " % val) + @property def run(self): """ set the default run action """ @@ -130,7 +154,7 @@ def run(self): @run.setter def run(self, val): - self._run = ConfigHelper.makeList(val) + self._run.extend(Action.makeListOfDictFromJSON(val)) @property def event(self): @@ -139,7 +163,7 @@ def event(self): @event.setter def event(self, val): - self._event = ConfigHelper.makeList(val) + self._event.extend(Action.makeListOfDictFromJSON(val)) @property def track(self): @@ -148,7 +172,7 @@ def track(self): @track.setter def track(self, val): - self._track = ConfigHelper.makeList(val) + self._track.extend(Action.makeListOfDictFromJSON(val)) @property def step(self): @@ -157,7 +181,7 @@ def step(self): @step.setter def step(self, val): - self._step = ConfigHelper.makeList(val) + self._step.extend(Action.makeListOfDictFromJSON(val)) @property def stack(self): @@ -166,4 +190,4 @@ def stack(self): @stack.setter def stack(self, val): - self._stack = ConfigHelper.makeList(val) + self._stack.extend(Action.makeListOfDictFromJSON(val)) From 6ae0a93ecab90da2e85c18cd5045885a961daec9 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sat, 3 Feb 2024 20:08:52 -0600 Subject: [PATCH 06/20] fix: placate flake8 --- DDG4/python/DDSim/Helper/Action.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index dc7dbf34f..4afcedb81 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -123,7 +123,6 @@ def calorimeterSDTypes(self): def calorimeterSDTypes(self, val): self._calorimeterSDTypes = ConfigHelper.makeList(val) - @staticmethod def makeListOfDictFromJSON(val): if isinstance(val, str): @@ -131,7 +130,7 @@ def makeListOfDictFromJSON(val): import json try: val = json.loads(val) - except: + except ValueError as e: val = tuple(val.split(",")) if isinstance(val, tuple): # assumes: ( "Geant4TestEventAction", {"Property_int": 10} ) @@ -141,7 +140,7 @@ def makeListOfDictFromJSON(val): if isinstance(val, dict): # assumes: { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } # creates: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] - val = [ val ] + val = [val] if isinstance(val, list): # assumes: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] return val From 83a89d35c05bf8bc4fee1a0097111cd1f0c0131b Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sat, 3 Feb 2024 21:06:14 -0600 Subject: [PATCH 07/20] fix: placate flake8 --- DDG4/python/DDSim/Helper/Action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index 4afcedb81..367c66154 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -130,7 +130,7 @@ def makeListOfDictFromJSON(val): import json try: val = json.loads(val) - except ValueError as e: + except ValueError: val = tuple(val.split(",")) if isinstance(val, tuple): # assumes: ( "Geant4TestEventAction", {"Property_int": 10} ) From 4ce8931741f8ba8d124aebaf2abf205599d544c4 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sun, 4 Feb 2024 09:40:19 -0600 Subject: [PATCH 08/20] fix: extended Action docstring --- DDG4/python/DDSim/Helper/Action.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index 367c66154..b58024583 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -30,14 +30,16 @@ class Action(ConfigHelper): >>> SIM = DD4hepSimulation() >>> SIM.action.mapActions['ecal'] =( "CaloPreShowerSDAction", {"FirstLayerNumber": 1} ) - Additional actions can be set as well with + Additional actions can be set as well with the following syntax variations: >>> SIM = DD4hepSimulation() - >>> SIM.action.run = [ ("Geant4TestRunAction", {"Property_int": 10} ) ] - >>> SIM.action.event = [ ("Geant4TestEventAction", {"Property_int": 10} ) ] - >>> SIM.action.track = [ ("Geant4TestTrackAction", {"Property_int": 10} ) ] - >>> SIM.action.step = [ ("Geant4TestStepAction", {"Property_int": 10} ) ] - >>> SIM.action.stack = [ ("Geant4TestStackAction", {"Property_int": 10} ) ] + >>> SIM.action.run = "Geant4TestRunAction" # name only + >>> SIM.action.event = "Geant4TestEventAction/EventAction0,Geant4TestEventAction/EventAction1" # comma-separated names + >>> SIM.action.track = ( "Geant4TestTrackAction", {"Property_int": 10} ) # tuple of name and parameter dict + >>> SIM.action.step = { "name": "Geant4TestStepAction", "parameter": {"Property_int": 10} } # dict of name and parameter dict + >>> SIM.action.stack = [ { "name": "Geant4TestStackAction", "parameter": {"Property_int": 10} } ] # list of dict of name and parameter dict + +On the command line, these can be specified as JSON strings. """ From f2b445baa9230b35d04be2fce270a28426fa80ec Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sun, 4 Feb 2024 09:50:53 -0600 Subject: [PATCH 09/20] fix: docstring line breaks for flake8 --- DDG4/python/DDSim/Helper/Action.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index b58024583..108b29e13 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -33,11 +33,16 @@ class Action(ConfigHelper): Additional actions can be set as well with the following syntax variations: >>> SIM = DD4hepSimulation() - >>> SIM.action.run = "Geant4TestRunAction" # name only - >>> SIM.action.event = "Geant4TestEventAction/EventAction0,Geant4TestEventAction/EventAction1" # comma-separated names - >>> SIM.action.track = ( "Geant4TestTrackAction", {"Property_int": 10} ) # tuple of name and parameter dict - >>> SIM.action.step = { "name": "Geant4TestStepAction", "parameter": {"Property_int": 10} } # dict of name and parameter dict - >>> SIM.action.stack = [ { "name": "Geant4TestStackAction", "parameter": {"Property_int": 10} } ] # list of dict of name and parameter dict + # single action by name only: + >>> SIM.action.run = "Geant4TestRunAction" + # multiple actions with comma-separated names: + >>> SIM.action.event = "Geant4TestEventAction/Action0,Geant4TestEventAction/Action1" + # single actuon by tuple of name and parameter dict: + >>> SIM.action.track = ( "Geant4TestTrackAction", {"Property_int": 10} ) + # single action by dict of name and parameter dict: + >>> SIM.action.step = { "name": "Geant4TestStepAction", "parameter": {"Property_int": 10} } + # multiple actions by list of dict of name and parameter dict: + >>> SIM.action.stack = [ { "name": "Geant4TestStackAction", "parameter": {"Property_int": 10} } ] On the command line, these can be specified as JSON strings. From cd08eb8eda27bbefe2a63c60f5033ce40a1dfa49 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sun, 4 Feb 2024 09:52:43 -0600 Subject: [PATCH 10/20] fix: split comma-separated string into list of dict --- DDG4/python/DDSim/Helper/Action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index 108b29e13..ec6fc8cc6 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -138,7 +138,7 @@ def makeListOfDictFromJSON(val): try: val = json.loads(val) except ValueError: - val = tuple(val.split(",")) + val = [dict(name=v) for v in val.split(",")] if isinstance(val, tuple): # assumes: ( "Geant4TestEventAction", {"Property_int": 10} ) # creates: { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } From cc9994b39b5e606d829f3f8224612b831fcc4040 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Mon, 5 Feb 2024 08:27:14 -0600 Subject: [PATCH 11/20] fix: typo Co-authored-by: Andre Sailer --- DDG4/python/DDSim/Helper/Action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index ec6fc8cc6..f87574ebf 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -37,7 +37,7 @@ class Action(ConfigHelper): >>> SIM.action.run = "Geant4TestRunAction" # multiple actions with comma-separated names: >>> SIM.action.event = "Geant4TestEventAction/Action0,Geant4TestEventAction/Action1" - # single actuon by tuple of name and parameter dict: + # single action by tuple of name and parameter dict: >>> SIM.action.track = ( "Geant4TestTrackAction", {"Property_int": 10} ) # single action by dict of name and parameter dict: >>> SIM.action.step = { "name": "Geant4TestStepAction", "parameter": {"Property_int": 10} } From 823c597ede16621cc42ebbc7f16f8bbfc27566a4 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Mon, 5 Feb 2024 13:26:03 -0600 Subject: [PATCH 12/20] fix: grammar Co-authored-by: Andre Sailer --- DDG4/python/DDSim/Helper/Action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index f87574ebf..70ddd95a8 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -142,7 +142,7 @@ def makeListOfDictFromJSON(val): if isinstance(val, tuple): # assumes: ( "Geant4TestEventAction", {"Property_int": 10} ) # creates: { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } - # note: not able to specified as json which only allows a list + # note: not able to be specified as json which only allows a list val = dict(name=val[0], parameter=val[1]) if isinstance(val, dict): # assumes: { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } From 74719e214940444625b863c073b9adc57cb26ee3 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Mon, 5 Feb 2024 14:46:32 -0600 Subject: [PATCH 13/20] doc: add json example --- DDG4/python/DDSim/Helper/Action.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index 70ddd95a8..0070cd2ee 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -44,7 +44,18 @@ class Action(ConfigHelper): # multiple actions by list of dict of name and parameter dict: >>> SIM.action.stack = [ { "name": "Geant4TestStackAction", "parameter": {"Property_int": 10} } ] -On the command line, these can be specified as JSON strings. +On the command line or in python, these actions can be specified as JSON strings: + $ ddsim --action.stack '{ "name": "Geant4TestStackAction", "parameter": { "Property_int": 10 } }' +or + >>> SIM.action.stack = ''' + { + "name": "Geant4TestStackAction", + "parameter": { + "Property_int": 10, + "Property_double": "1.0*mm" + } + } + ''' """ From 028c796402473cbae70a952eb0042de0d916ba76 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Mon, 5 Feb 2024 16:24:46 -0600 Subject: [PATCH 14/20] fix: allow dict without parameter key --- DDG4/python/DDSim/DD4hepSimulation.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DDG4/python/DDSim/DD4hepSimulation.py b/DDG4/python/DDSim/DD4hepSimulation.py index 0917f7790..18a88fdf9 100644 --- a/DDG4/python/DDSim/DD4hepSimulation.py +++ b/DDG4/python/DDSim/DD4hepSimulation.py @@ -357,8 +357,9 @@ def run(self): (self.action.stack, DDG4.StackingAction, kernel.stackingAction)]: for action_dict in action_list: action = DDG4_Action(kernel, action_dict["name"]) - for parameter, value in action_dict['parameter'].items(): - setattr(action, parameter, value) + if 'parameter' in action_dict.keys(): + for parameter, value in action_dict['parameter'].items(): + setattr(action, parameter, value) kernel_Action().add(action) # ---------------------------------------------------------------------------------- From e5834cf852c6a0bc99db0332048deef75eed9140 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Mon, 5 Feb 2024 18:58:15 -0600 Subject: [PATCH 15/20] feat: unit tests for ddsim actions (no output checks) --- DDTest/CMakeLists.txt | 17 +- DDTest/python/userActionsSteeringFile.PY | 558 ++++++++++++++++++ ...ringFile.PY => userPluginsSteeringFile.PY} | 0 3 files changed, 573 insertions(+), 2 deletions(-) create mode 100644 DDTest/python/userActionsSteeringFile.PY rename DDTest/python/{userSteeringFile.PY => userPluginsSteeringFile.PY} (100%) diff --git a/DDTest/CMakeLists.txt b/DDTest/CMakeLists.txt index 135c1bedf..f3424d10d 100644 --- a/DDTest/CMakeLists.txt +++ b/DDTest/CMakeLists.txt @@ -140,8 +140,21 @@ if (DD4HEP_USE_GEANT4) add_test( t_ddsimUserPlugins "${CMAKE_INSTALL_PREFIX}/bin/run_test.sh" ddsim --compactFile=${CMAKE_INSTALL_PREFIX}/DDDetectors/compact/SiD.xml --runType=batch -N=10 - --outputFile=t_ddsimUserPlugins.root -G --steeringFile ${CMAKE_CURRENT_SOURCE_DIR}/python/userSteeringFile.PY - --part.userParticleHandler=) + --outputFile=t_ddsimUserPlugins.root -G + --steeringFile ${CMAKE_CURRENT_SOURCE_DIR}/python/userPluginsSteeringFile.PY + --part.userParticleHandler= + ) + + add_test( t_ddsimUserActions "${CMAKE_INSTALL_PREFIX}/bin/run_test.sh" + ddsim --compactFile=${CMAKE_INSTALL_PREFIX}/DDDetectors/compact/SiD.xml --runType=batch -N=10 + --outputFile=t_ddsimUserActions.root -G + --steeringFile ${CMAKE_CURRENT_SOURCE_DIR}/python/userActionsSteeringFile.PY + --action.event "Geant4TestEventAction/EventActionCLI1" + --action.step "Geant4TestStepAction/StepActionCLI1,Geant4TestStepAction/StepActionCLI2" + --action.step '[ "Geant4TestStepAction/StepActionCLI2", "Geant4TestStepAction/StepActionCLI3" ]' + --action.stack '{ "name" : "Geant4TestStackAction/StackActionCLI1" , "parameter" : { "Property_int" : 10 } }' + --action.stack '[ { "name" : "Geant4TestStackAction/StackActionCLI2" , "parameter" : { "Property_int" : 10 } } ]' + ) endif() install(DIRECTORY include/DD4hep DESTINATION include) diff --git a/DDTest/python/userActionsSteeringFile.PY b/DDTest/python/userActionsSteeringFile.PY new file mode 100644 index 000000000..5de07feaf --- /dev/null +++ b/DDTest/python/userActionsSteeringFile.PY @@ -0,0 +1,558 @@ +from DDSim.DD4hepSimulation import DD4hepSimulation +from g4units import mm, GeV, MeV +SIM = DD4hepSimulation() + +## The compact XML file, or multiple compact files, if the last one is the closer. +SIM.compactFile = [] +## Lorentz boost for the crossing angle, in radian! +SIM.crossingAngleBoost = 0.0 +SIM.enableDetailedShowerMode = False +SIM.enableG4GPS = False +SIM.enableG4Gun = False +SIM.enableGun = False +## InputFiles for simulation .stdhep, .slcio, .HEPEvt, .hepevt, .pairs, .hepmc, .hepmc.gz, .hepmc.xz, .hepmc.bz2, .hepmc3, .hepmc3.gz, .hepmc3.xz, .hepmc3.bz2, .hepmc3.tree.root files are supported +SIM.inputFiles = [] +## Macro file to execute for runType 'run' or 'vis' +SIM.macroFile = "" +## number of events to simulate, used in batch mode +SIM.numberOfEvents = 0 +## Outputfile from the simulation: .slcio, edm4hep.root and .root output files are supported +SIM.outputFile = "dummyOutput.slcio" +## Physics list to use in simulation +SIM.physicsList = None +## Verbosity use integers from 1(most) to 7(least) verbose +## or strings: VERBOSE, DEBUG, INFO, WARNING, ERROR, FATAL, ALWAYS +SIM.printLevel = 3 +## The type of action to do in this invocation +## batch: just simulate some events, needs numberOfEvents, and input file or gun +## vis: enable visualisation, run the macroFile if it is set +## qt: enable visualisation in Qt shell, run the macroFile if it is set +## run: run the macroFile and exit +## shell: enable interactive session +SIM.runType = "batch" +## Skip first N events when reading a file +SIM.skipNEvents = 0 +## Steering file to change default behaviour +SIM.steeringFile = None +## FourVector of translation for the Smearing of the Vertex position: x y z t +SIM.vertexOffset = [0.0, 0.0, 0.0, 0.0] +## FourVector of the Sigma for the Smearing of the Vertex position: x y z t +SIM.vertexSigma = [0.0, 0.0, 0.0, 0.0] + + +################################################################################ +## Helper holding sensitive detector actions. +## +## The default tracker and calorimeter actions can be set with +## +## >>> SIM = DD4hepSimulation() +## >>> SIM.action.tracker=('Geant4TrackerWeightedAction', {'HitPositionCombination': 2, 'CollectSingleDeposits': False}) +## >>> SIM.action.calo = "Geant4CalorimeterAction" +## +## The default sensitive actions for calorimeters and trackers are applied based on the sensitive type. +## The list of sensitive types can be changed with +## +## >>> SIM = DD4hepSimulation() +## >>> SIM.action.trackerSDTypes = ['tracker', 'myTrackerSensType'] +## >>> SIM.calor.calorimeterSDTypes = ['calorimeter', 'myCaloSensType'] +## +## For specific subdetectors specific sensitive detectors can be set based on patterns in the name of the subdetector. +## +## >>> SIM = DD4hepSimulation() +## >>> SIM.action.mapActions['tpc'] = "TPCSDAction" +## +## and additional parameters for the sensitive detectors can be set when the map is given a tuple +## +## >>> SIM = DD4hepSimulation() +## >>> SIM.action.mapActions['ecal'] =( "CaloPreShowerSDAction", {"FirstLayerNumber": 1} ) +## +## +## Additional actions can be set as well with the following syntax variations: +## +## >>> SIM = DD4hepSimulation() +## # single action by name only: +## >>> SIM.action.run = "Geant4TestRunAction" +## # multiple actions with comma-separated names: +## >>> SIM.action.event = "Geant4TestEventAction/Action0,Geant4TestEventAction/Action1" +## # single action by tuple of name and parameter dict: +## >>> SIM.action.track = ( "Geant4TestTrackAction", {"Property_int": 10} ) +## # single action by dict of name and parameter dict: +## >>> SIM.action.step = { "name": "Geant4TestStepAction", "parameter": {"Property_int": 10} } +## # multiple actions by list of dict of name and parameter dict: +## >>> SIM.action.stack = [ { "name": "Geant4TestStackAction", "parameter": {"Property_int": 10} } ] +## +## On the command line or in python, these actions can be specified as JSON strings: +## $ ddsim --action.stack '{ "name": "Geant4TestStackAction", "parameter": { "Property_int": 10 } }' +## or +## >>> SIM.action.stack = ''' +## { +## "name": "Geant4TestStackAction", +## "parameter": { +## "Property_int": 10, +## "Property_double": "1.0*mm" +## } +## } +## ''' +## +## +################################################################################ + +## set the default calorimeter action +SIM.action.calo = "Geant4ScintillatorCalorimeterAction" + +## List of patterns matching sensitive detectors of type Calorimeter. +SIM.action.calorimeterSDTypes = ['calorimeter'] + +## Create a map of patterns and actions to be applied to sensitive detectors. +## +## Example: if the name of the detector matches 'tpc' the TPCSDAction is used. +## +## SIM.action.mapActions['tpc'] = "TPCSDAction" +## +SIM.action.mapActions = {} + +## set the default tracker action +SIM.action.tracker = ('Geant4TrackerWeightedAction', {'HitPositionCombination': 2, 'CollectSingleDeposits': False}) + +## List of patterns matching sensitive detectors of type Tracker. +SIM.action.trackerSDTypes = ['tracker'] + +## single action by name only +SIM.action.run = "Geant4TestRunAction/RunAction1" + +## multiple actions with comma-separated names: +SIM.action.event = "Geant4TestEventAction/EventAction0,Geant4TestEventAction/EventAction1" + +## single action by tuple of name and parameter dict: +SIM.action.track = ( "Geant4TestTrackAction/TrackAction1", {"Property_int": 10} ) + +## single action by dict of name and parameter dict: +SIM.action.step = { "name": "Geant4TestStepAction/StepAction1", "parameter": {"Property_int": 10} } + +## multiple actions by list of dict of name and parameter dict: +SIM.action.stack = [ { "name": "Geant4TestStackAction/StackAction1", "parameter": {"Property_int": 10} } ] + +## On the command line or in python, these actions can be specified as JSON strings: +SIM.action.stack = ''' +{ + "name": "Geant4TestStackAction/StackActionJSON1", + "parameter": { + "Property_int": 10, + "Property_double": "1.0*mm" + } +} +''' + + + +################################################################################ +## Configuration for the magnetic field (stepper) +################################################################################ +SIM.field.delta_chord = 0.25 +SIM.field.delta_intersection = 0.001 +SIM.field.delta_one_step = 0.01 +SIM.field.eps_max = 0.001 +SIM.field.eps_min = 5e-05 +SIM.field.equation = "Mag_UsualEqRhs" +SIM.field.largest_step = 10000.0 +SIM.field.min_chord_step = 0.01 +SIM.field.stepper = "ClassicalRK4" + + +################################################################################ +## Configuration for sensitive detector filters +## +## Set the default filter for 'tracker' +## >>> SIM.filter.tracker = "edep1kev" +## Use no filter for 'calorimeter' by default +## >>> SIM.filter.calo = "" +## +## Assign a filter to a sensitive detector via pattern matching +## >>> SIM.filter.mapDetFilter['FTD'] = "edep1kev" +## +## Or more than one filter: +## >>> SIM.filter.mapDetFilter['FTD'] = ["edep1kev", "geantino"] +## +## Don't use the default filter or anything else: +## >>> SIM.filter.mapDetFilter['TPC'] = None ## or "" or [] +## +## Create a custom filter. The dictionary is used to instantiate the filter later on +## >>> SIM.filter.filters['edep3kev'] = dict(name="EnergyDepositMinimumCut/3keV", parameter={"Cut": 3.0*keV} ) +## +## +################################################################################ + +## +## default filter for calorimeter sensitive detectors; +## this is applied if no other filter is used for a calorimeter +## +SIM.filter.calo = "edep0" + +## list of filter objects: map between name and parameter dictionary +SIM.filter.filters = {'geantino': {'name': 'GeantinoRejectFilter/GeantinoRejector', 'parameter': {}}, 'edep1kev': {'name': 'EnergyDepositMinimumCut', 'parameter': {'Cut': 0.001}}, 'edep0': {'name': 'EnergyDepositMinimumCut/Cut0', 'parameter': {'Cut': 0.0}}} + +## a map between patterns and filter objects, using patterns to attach filters to sensitive detector +SIM.filter.mapDetFilter = {} + +## default filter for tracking sensitive detectors; this is applied if no other filter is used for a tracker +SIM.filter.tracker = "edep1kev" + + +################################################################################ +## Configuration for the Detector Construction. +################################################################################ +SIM.geometry.dumpGDML = "" +SIM.geometry.dumpHierarchy = 0 + +## Print Debug information about Elements +SIM.geometry.enableDebugElements = False + +## Print Debug information about Materials +SIM.geometry.enableDebugMaterials = False + +## Print Debug information about Placements +SIM.geometry.enableDebugPlacements = False + +## Print Debug information about Reflections +SIM.geometry.enableDebugReflections = False + +## Print Debug information about Regions +SIM.geometry.enableDebugRegions = False + +## Print Debug information about Shapes +SIM.geometry.enableDebugShapes = False + +## Print Debug information about Surfaces +SIM.geometry.enableDebugSurfaces = False + +## Print Debug information about Volumes +SIM.geometry.enableDebugVolumes = False + +## Print information about placements +SIM.geometry.enablePrintPlacements = False + +## Print information about Sensitives +SIM.geometry.enablePrintSensitives = False + + +################################################################################ +## Configuration for the GuineaPig InputFiles +################################################################################ + +## Set the number of pair particles to simulate per event. +## Only used if inputFile ends with ".pairs" +## If "-1" all particles will be simulated in a single event +## +SIM.guineapig.particlesPerEvent = "-1" + + +################################################################################ +## Configuration for the DDG4 ParticleGun +################################################################################ + +## direction of the particle gun, 3 vector +SIM.gun.direction = (0, 0, 1) + +## choose the distribution of the random direction for theta +## +## Options for random distributions: +## +## 'uniform' is the default distribution, flat in theta +## 'cos(theta)' is flat in cos(theta) +## 'eta', or 'pseudorapidity' is flat in pseudorapity +## 'ffbar' is distributed according to 1+cos^2(theta) +## +## Setting a distribution will set isotrop = True +## +SIM.gun.distribution = None + +## Total energy (including mass) for the particle gun. +## +## If not None, it will overwrite the setting of momentumMin and momentumMax +SIM.gun.energy = None + +## Maximal pseudorapidity for random distibution (overrides thetaMin) +SIM.gun.etaMax = None + +## Minimal pseudorapidity for random distibution (overrides thetaMax) +SIM.gun.etaMin = None + +## isotropic distribution for the particle gun +## +## use the options phiMin, phiMax, thetaMin, and thetaMax to limit the range of randomly distributed directions +## if one of these options is not None the random distribution will be set to True and cannot be turned off! +## +SIM.gun.isotrop = False + +## Maximal momentum when using distribution (default = 0.0) +SIM.gun.momentumMax = 10000.0 + +## Minimal momentum when using distribution (default = 0.0) +SIM.gun.momentumMin = 0.0 +SIM.gun.multiplicity = 1 +SIM.gun.particle = "mu-" + +## Maximal azimuthal angle for random distribution +SIM.gun.phiMax = None + +## Minimal azimuthal angle for random distribution +SIM.gun.phiMin = None + +## position of the particle gun, 3 vector +SIM.gun.position = (0.0, 0.0, 0.0) + +## Maximal polar angle for random distribution +SIM.gun.thetaMax = None + +## Minimal polar angle for random distribution +SIM.gun.thetaMin = None + + +################################################################################ +## Configuration for the hepmc3 InputFiles +################################################################################ + +## Set the name of the attribute contraining color flow information index 0. +SIM.hepmc3.Flow1 = "flow1" + +## Set the name of the attribute contraining color flow information index 1. +SIM.hepmc3.Flow2 = "flow2" + +## Set to false if the input should be opened with the hepmc2 ascii reader. +## +## If ``True`` a '.hepmc' file will be opened with the HEPMC3 Reader Factory. +## +## Defaults to true if DD4hep was build with HEPMC3 support. +## +SIM.hepmc3.useHepMC3 = False + + +################################################################################ +## Configuration for Input Files. +################################################################################ + +## Set one or more functions to configure input steps. +## +## The functions must take a ``DD4hepSimulation`` object as their only argument and return the created generatorAction +## ``gen`` (for example). +## +## For example one can add this to the ddsim steering file: +## +## def exampleUserPlugin(dd4hepSimulation): +## '''Example code for user created plugin. +## +## :param DD4hepSimulation dd4hepSimulation: The DD4hepSimulation instance, so all parameters can be accessed +## :return: GeneratorAction +## ''' +## from DDG4 import GeneratorAction, Kernel +## # Geant4InputAction is the type of plugin, Cry1 just an identifier +## gen = GeneratorAction(Kernel(), 'Geant4InputAction/Cry1' , True) +## # CRYEventReader is the actual plugin, steeringFile its constructor parameter +## gen.Input = 'CRYEventReader|' + 'steeringFile' +## # we can give a dictionary of Parameters that has to be interpreted by the setParameters function of the plugin +## gen.Parameters = {'DataFilePath': '/path/to/files/data'} +## gen.enableUI() +## return gen +## +## SIM.inputConfig.userInputPlugin = exampleUserPlugin +## +## Repeat function definition and assignment to add multiple input steps +## +## +SIM.inputConfig.userInputPlugin = [] + + +################################################################################ +## Configuration for the generator-level InputFiles +################################################################################ + +## Set the name of the collection containing the MCParticle input. +## Default is "MCParticle". +## +SIM.lcio.mcParticleCollectionName = "MCParticle" + + +################################################################################ +## Configuration for the LCIO output file settings +################################################################################ + +## The event number offset to write in slcio output file. E.g setting it to 42 will start counting events from 42 instead of 0 +SIM.meta.eventNumberOffset = 0 + +## Event parameters to write in every event. Use C/F/I ids to specify parameter type. E.g parameterName/F=0.42 to set a float parameter +SIM.meta.eventParameters = [] + +## The run number offset to write in slcio output file. E.g setting it to 42 will start counting runs from 42 instead of 0 +SIM.meta.runNumberOffset = 0 + + +################################################################################ +## Configuration for the output levels of DDG4 components +################################################################################ + +## Output level for geometry. +SIM.output.geometry = 2 + +## Output level for input sources +SIM.output.inputStage = 3 + +## Output level for Geant4 kernel +SIM.output.kernel = 3 + +## Output level for ParticleHandler +SIM.output.part = 3 + +## Output level for Random Number Generator setup +SIM.output.random = 6 + + +################################################################################ +## Configuration for Output Files. +################################################################################ + +## Set a function to configure the outputFile. +## +## The function must take a ``DD4hepSimulation`` object as its only argument and return ``None``. +## +## For example one can add this to the ddsim steering file: +## +## def exampleUserPlugin(dd4hepSimulation): +## '''Example code for user created plugin. +## +## :param DD4hepSimulation dd4hepSimulation: The DD4hepSimulation instance, so all parameters can be accessed +## :return: None +## ''' +## from DDG4 import EventAction, Kernel +## dd = dd4hepSimulation # just shorter variable name +## evt_root = EventAction(Kernel(), 'Geant4Output2ROOT/' + dd.outputFile, True) +## evt_root.HandleMCTruth = True or False +## evt_root.Control = True +## if not dd.outputFile.endswith(dd.outputConfig.myExtension): +## output = dd.outputFile + dd.outputConfig.myExtension +## evt_root.Output = output +## evt_root.enableUI() +## Kernel().eventAction().add(evt_root) +## return None +## +## SIM.outputConfig.userOutputPlugin = exampleUserPlugin +## # arbitrary options can be created and set via the steering file or command line +## SIM.outputConfig.myExtension = '.csv' +## +SIM.outputConfig.userOutputPlugin = None + + +################################################################################ +## Configuration for the Particle Handler/ MCTruth treatment +################################################################################ + +## Enable lots of printout on simulated hits and MC-truth information +SIM.part.enableDetailedHitsAndParticleInfo = False + +## Keep all created particles +SIM.part.keepAllParticles = False + +## Minimal distance between particle vertex and endpoint of parent after +## which the vertexIsNotEndpointOfParent flag is set +## +SIM.part.minDistToParentVertex = 2.2e-14 + +## MinimalKineticEnergy to store particles created in the tracking region +SIM.part.minimalKineticEnergy = 1.0 + +## Printout at End of Tracking +SIM.part.printEndTracking = False + +## Printout at Start of Tracking +SIM.part.printStartTracking = False + +## List of processes to save, on command line give as whitespace separated string in quotation marks +SIM.part.saveProcesses = ['Decay'] + +## Optionally enable an extended Particle Handler +SIM.part.userParticleHandler = "Geant4TCUserParticleHandler" + + +################################################################################ +## Configuration for the PhysicsList +################################################################################ + +## If true, add decay processes for all particles. +## +## Only enable when creating a physics list not based on an existing Geant4 list! +## +SIM.physics.decays = False + +## The name of the Geant4 Physics list. +SIM.physics.list = "FTFP_BERT" + +## location of particle.tbl file containing extra particles and their lifetime information +## +## For example in $DD4HEP/examples/DDG4/examples/particle.tbl +## +SIM.physics.pdgfile = None + +## The global geant4 rangecut for secondary production +## +## Default is 0.7 mm as is the case in geant4 10 +## +## To disable this plugin and be absolutely sure to use the Geant4 default range cut use "None" +## +## Set printlevel to DEBUG to see a printout of all range cuts, +## but this only works if range cut is not "None" +## +SIM.physics.rangecut = 0.7 + +## Set of PDG IDs that will not be passed from the input record to Geant4. +## +## Quarks, gluons and W's Z's etc should not be treated by Geant4 +## +SIM.physics.rejectPDGs = {1, 2, 3, 4, 5, 6, 3201, 3203, 4101, 4103, 21, 23, 24, 5401, 25, 2203, 5403, 3101, 3103, 4403, 2101, 5301, 2103, 5303, 4301, 1103, 4303, 5201, 5203, 3303, 4201, 4203, 5101, 5103, 5503} + +## Set of PDG IDs for particles that should not be passed to Geant4 if their properTime is 0. +## +## The properTime of 0 indicates a documentation to add FSR to a lepton for example. +## +SIM.physics.zeroTimePDGs = {17, 11, 13, 15} + +def setupCerenkovScint(kernel): + from DDG4 import PhysicsList + seq = kernel.physicsList() + + scint = PhysicsList(kernel, 'Geant4ScintillationPhysics/ScintillationPhys') + scint.VerboseLevel = 0 + scint.TrackSecondariesFirst = True + scint.enableUI() + seq.adopt(scint) + + cerenkov = PhysicsList(kernel, 'Geant4CerenkovPhysics/CerenkovPhys') + cerenkov.VerboseLevel = 0 + cerenkov.MaxNumPhotonsPerStep = 10 + cerenkov.MaxBetaChangePerStep = 10.0 + cerenkov.TrackSecondariesFirst = True + cerenkov.enableUI() + seq.adopt(cerenkov) + + ph = PhysicsList(kernel, 'Geant4OpticalPhotonPhysics/OpticalGammaPhys') + ph.addParticleConstructor('G4OpticalPhoton') + ph.VerboseLevel = 0 + ph.enableUI() + seq.adopt(ph) + + return None + + +SIM.physics.setupUserPhysics(setupCerenkovScint) + + +################################################################################ +## Properties for the random number generator +################################################################################ + +## If True, calculate random seed for each event basedon eventID and runID +## Allows reproducibility even whenSkippingEvents +SIM.random.enableEventSeed = False +SIM.random.file = None +SIM.random.luxury = 1 +SIM.random.replace_gRandom = True +SIM.random.seed = None +SIM.random.type = None diff --git a/DDTest/python/userSteeringFile.PY b/DDTest/python/userPluginsSteeringFile.PY similarity index 100% rename from DDTest/python/userSteeringFile.PY rename to DDTest/python/userPluginsSteeringFile.PY From e166b191c71456714fd125010e8129be744a2302 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Tue, 6 Feb 2024 08:07:35 -0600 Subject: [PATCH 16/20] fix: use dict.get with default empty Co-authored-by: Andre Sailer --- DDG4/python/DDSim/DD4hepSimulation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/DDG4/python/DDSim/DD4hepSimulation.py b/DDG4/python/DDSim/DD4hepSimulation.py index 18a88fdf9..f63b49f41 100644 --- a/DDG4/python/DDSim/DD4hepSimulation.py +++ b/DDG4/python/DDSim/DD4hepSimulation.py @@ -357,9 +357,8 @@ def run(self): (self.action.stack, DDG4.StackingAction, kernel.stackingAction)]: for action_dict in action_list: action = DDG4_Action(kernel, action_dict["name"]) - if 'parameter' in action_dict.keys(): - for parameter, value in action_dict['parameter'].items(): - setattr(action, parameter, value) + for parameter, value in action_dict.get('parameter', {}).items(): + setattr(action, parameter, value) kernel_Action().add(action) # ---------------------------------------------------------------------------------- From 02fa0847655c832a2161b568e90163617e4c58de Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Fri, 9 Feb 2024 22:15:00 -0600 Subject: [PATCH 17/20] fix: correct quoting of DDTest command line json --- DDTest/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DDTest/CMakeLists.txt b/DDTest/CMakeLists.txt index f3424d10d..bc4d0b13d 100644 --- a/DDTest/CMakeLists.txt +++ b/DDTest/CMakeLists.txt @@ -151,9 +151,9 @@ if (DD4HEP_USE_GEANT4) --steeringFile ${CMAKE_CURRENT_SOURCE_DIR}/python/userActionsSteeringFile.PY --action.event "Geant4TestEventAction/EventActionCLI1" --action.step "Geant4TestStepAction/StepActionCLI1,Geant4TestStepAction/StepActionCLI2" - --action.step '[ "Geant4TestStepAction/StepActionCLI2", "Geant4TestStepAction/StepActionCLI3" ]' - --action.stack '{ "name" : "Geant4TestStackAction/StackActionCLI1" , "parameter" : { "Property_int" : 10 } }' - --action.stack '[ { "name" : "Geant4TestStackAction/StackActionCLI2" , "parameter" : { "Property_int" : 10 } } ]' + --action.step '\[ \"Geant4TestStepAction/StepActionCLI3\" , \"Geant4TestStepAction/StepActionCLI4\" \]' + --action.stack '\{ \"name\" : \"Geant4TestStackAction/StackActionCLI1\" , \"parameter\" : \{ \"Property_int\" : 10 \} \}' + --action.stack '\[ \{ \"name\" : \"Geant4TestStackAction/StackActionCLI2\" , \"parameter\" : { \"Property_int\" : 10 \} \} \]' ) endif() From 62b7b14e6f2c764e17ee862be8dfc24b8f6cb773 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sat, 10 Feb 2024 11:31:39 -0600 Subject: [PATCH 18/20] fix: accept list of str as action argument --- DDG4/python/DDSim/Helper/Action.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index 0070cd2ee..2d17c9b05 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -160,8 +160,15 @@ def makeListOfDictFromJSON(val): # creates: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] val = [val] if isinstance(val, list): - # assumes: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] - return val + if not val: + # empty list + return [] + if isinstance(val[0], str): + # assumes: [ "Geant4TestEventAction", "Geant4TestEventAction" ] + return [dict(name=v) for v in val] + if isinstance(val[0], dict): + # assumes: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] + return val raise RuntimeError("Commandline setting of action is not successful for: %s " % val) @property From c452e5ada237bcac56f7f010a2769f6af67768ed Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sat, 10 Feb 2024 20:27:00 -0600 Subject: [PATCH 19/20] fix: action=append for argparse; deduplicate; recursive makeListOfDictFromJSON --- DDG4/python/DDSim/Helper/Action.py | 49 ++++++++++++++++++------------ DDTest/CMakeLists.txt | 4 +++ 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/DDG4/python/DDSim/Helper/Action.py b/DDG4/python/DDSim/Helper/Action.py index 2d17c9b05..94bd505aa 100644 --- a/DDG4/python/DDSim/Helper/Action.py +++ b/DDG4/python/DDSim/Helper/Action.py @@ -67,10 +67,15 @@ def __init__(self): self._trackerSDTypes = ['tracker'] self._calorimeterSDTypes = ['calorimeter'] self._run = [] + self._run_EXTRA = {"action": "append"} self._event = [] + self._event_EXTRA = {"action": "append"} self._track = [] + self._track_EXTRA = {"action": "append"} self._step = [] + self._step_EXTRA = {"action": "append"} self._stack = [] + self._stack_EXTRA = {"action": "append"} self._closeProperties() @property @@ -148,27 +153,23 @@ def makeListOfDictFromJSON(val): import json try: val = json.loads(val) + # interpret json structure + return Action.makeListOfDictFromJSON(val) except ValueError: - val = [dict(name=v) for v in val.split(",")] + # returns: [ { "name": "Geant4TestEventAction" } ] + return [dict(name=v) for v in val.split(",")] if isinstance(val, tuple): # assumes: ( "Geant4TestEventAction", {"Property_int": 10} ) - # creates: { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } + # returns: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] # note: not able to be specified as json which only allows a list - val = dict(name=val[0], parameter=val[1]) + return [dict(name=val[0], parameter=val[1])] if isinstance(val, dict): # assumes: { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } - # creates: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] - val = [val] + # returns: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] + return [val] if isinstance(val, list): - if not val: - # empty list - return [] - if isinstance(val[0], str): - # assumes: [ "Geant4TestEventAction", "Geant4TestEventAction" ] - return [dict(name=v) for v in val] - if isinstance(val[0], dict): - # assumes: [ { "name": "Geant4TestEventAction", "parameter": {"Property_int": 10} } ] - return val + # interpret each list entry into a list and concatenate + return [i for v in val for i in Action.makeListOfDictFromJSON(v)] raise RuntimeError("Commandline setting of action is not successful for: %s " % val) @property @@ -178,7 +179,9 @@ def run(self): @run.setter def run(self, val): - self._run.extend(Action.makeListOfDictFromJSON(val)) + for action in Action.makeListOfDictFromJSON(val): + if action not in self._run: + self._run.append(action) @property def event(self): @@ -187,7 +190,9 @@ def event(self): @event.setter def event(self, val): - self._event.extend(Action.makeListOfDictFromJSON(val)) + for action in Action.makeListOfDictFromJSON(val): + if action not in self._event: + self._event.append(action) @property def track(self): @@ -196,7 +201,9 @@ def track(self): @track.setter def track(self, val): - self._track.extend(Action.makeListOfDictFromJSON(val)) + for action in Action.makeListOfDictFromJSON(val): + if action not in self._track: + self._track.append(action) @property def step(self): @@ -205,7 +212,9 @@ def step(self): @step.setter def step(self, val): - self._step.extend(Action.makeListOfDictFromJSON(val)) + for action in Action.makeListOfDictFromJSON(val): + if action not in self._step: + self._step.append(action) @property def stack(self): @@ -214,4 +223,6 @@ def stack(self): @stack.setter def stack(self, val): - self._stack.extend(Action.makeListOfDictFromJSON(val)) + for action in Action.makeListOfDictFromJSON(val): + if action not in self._stack: + self._stack.append(action) diff --git a/DDTest/CMakeLists.txt b/DDTest/CMakeLists.txt index bc4d0b13d..56c67459a 100644 --- a/DDTest/CMakeLists.txt +++ b/DDTest/CMakeLists.txt @@ -154,6 +154,10 @@ if (DD4HEP_USE_GEANT4) --action.step '\[ \"Geant4TestStepAction/StepActionCLI3\" , \"Geant4TestStepAction/StepActionCLI4\" \]' --action.stack '\{ \"name\" : \"Geant4TestStackAction/StackActionCLI1\" , \"parameter\" : \{ \"Property_int\" : 10 \} \}' --action.stack '\[ \{ \"name\" : \"Geant4TestStackAction/StackActionCLI2\" , \"parameter\" : { \"Property_int\" : 10 \} \} \]' + --printLevel VERBOSE + ) + set_tests_properties( t_ddsimUserActions PROPERTIES + PASS_REGULAR_EXPRESSION "Deleting object StepActionCLI1" ) endif() From 292bcead1a3630fd9fa34a389f502a1f012fac27 Mon Sep 17 00:00:00 2001 From: MarkusFrankATcernch Date: Mon, 12 Feb 2024 14:36:57 +0100 Subject: [PATCH 20/20] Update Geant4TestActions.cpp Explicity set namespace to TrackClassification in TestStackingAction::classifyNewTrack --- DDG4/src/Geant4TestActions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DDG4/src/Geant4TestActions.cpp b/DDG4/src/Geant4TestActions.cpp index 28ed166fd..9f7e13876 100644 --- a/DDG4/src/Geant4TestActions.cpp +++ b/DDG4/src/Geant4TestActions.cpp @@ -203,7 +203,7 @@ void Geant4TestStackAction::prepare(G4StackManager*) { PRINT("%s> calling prepare()", m_type.c_str()); } /// Return TrackClassification with enum G4ClassificationOfNewTrack or NoTrackClassification -TrackClassification Geant4TestStackAction::classifyNewTrack(G4StackManager*, const G4Track* trk) { +dd4hep::sim::TrackClassification Geant4TestStackAction::classifyNewTrack(G4StackManager*, const G4Track* trk) { PRINT("%s> calling classifyNewTrack(track=%d, parent=%d, position=(%f,%f,%f) Context: run=%p evt=%p)", m_type.c_str(), trk->GetTrackID(), trk->GetParentID(), trk->GetPosition().x(), trk->GetPosition().y(), trk->GetPosition().z(),