From 1045e37182a0763a9c6a75bf1f49bfd9a0e71f85 Mon Sep 17 00:00:00 2001 From: majacquet Date: Wed, 20 Mar 2024 15:50:34 +0100 Subject: [PATCH 1/5] Development of an actor which split particles at the entrance and/or at the exit of the volume --- core/opengate_core/opengate_core.cpp | 3 + .../GateSurfaceSplittingActor.cpp | 86 ++++++++++ .../opengate_lib/GateSurfaceSplittingActor.h | 45 +++++ .../pyGateSurfaceSplittingActor.cpp | 19 +++ opengate/actors/actorbuilders.py | 2 + opengate/actors/miscactors.py | 33 ++++ opengate/managers.py | 3 + ...73_geometrical_splitting_volume_surface.py | 161 ++++++++++++++++++ 8 files changed, 352 insertions(+) create mode 100644 core/opengate_core/opengate_lib/GateSurfaceSplittingActor.cpp create mode 100644 core/opengate_core/opengate_lib/GateSurfaceSplittingActor.h create mode 100644 core/opengate_core/opengate_lib/pyGateSurfaceSplittingActor.cpp create mode 100644 opengate/tests/src/test073_geometrical_splitting_volume_surface.py diff --git a/core/opengate_core/opengate_core.cpp b/core/opengate_core/opengate_core.cpp index 86e314219..74506b5e4 100644 --- a/core/opengate_core/opengate_core.cpp +++ b/core/opengate_core/opengate_core.cpp @@ -259,6 +259,8 @@ void init_GateARFTrainingDatasetActor(py::module &m); void init_GateKillActor(py::module &); +void init_GateSurfaceSplittingActor(py::module &); + void init_itk_image(py::module &); void init_GateImageNestedParameterisation(py::module &); @@ -493,6 +495,7 @@ PYBIND11_MODULE(opengate_core, m) { init_GateARFActor(m); init_GateARFTrainingDatasetActor(m); init_GateKillActor(m); + init_GateSurfaceSplittingActor(m); init_GateDigiAttributeManager(m); init_GateVDigiAttribute(m); init_GateExceptionHandler(m); diff --git a/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.cpp b/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.cpp new file mode 100644 index 000000000..53b88c804 --- /dev/null +++ b/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.cpp @@ -0,0 +1,86 @@ +/* -------------------------------------------------- + Copyright (C): OpenGATE Collaboration + This software is distributed under the terms + of the GNU Lesser General Public Licence (LGPL) + See LICENSE.md for further details + ------------------------------------ -------------- */ + +#include "GateSurfaceSplittingActor.h" +#include "G4ios.hh" +#include "GateHelpers.h" +#include "GateHelpersDict.h" +#include "G4LogicalVolumeStore.hh" + +GateSurfaceSplittingActor::GateSurfaceSplittingActor(py::dict &user_info) + : GateVActor(user_info, false) { + fActions.insert("StartSimulationAction"); + fActions.insert("SteppingAction"); + fActions.insert("PreUserTrackingAction"); + fMotherVolumeName = DictGetStr(user_info,"mother"); + fWeightThreshold = DictGetBool(user_info,"weight_threshold"); + fSplittingFactor = DictGetInt(user_info,"splitting_factor"); + fSplitEnteringParticles = DictGetBool(user_info,"split_entering_particles"); + fSplitExitingParticles = DictGetBool(user_info,"split_exiting_particles"); +} + +void GateSurfaceSplittingActor::ActorInitialize() {} + +void GateSurfaceSplittingActor::StartSimulationAction() { fNbOfKilledParticles = 0; } + +void GateSurfaceSplittingActor::PreUserTrackingAction(const G4Track* track){ + + fIsFirstStep = true; +} + +void GateSurfaceSplittingActor::SteppingAction(G4Step *step) { + auto track = step->GetTrack(); + auto weight = track->GetWeight(); + + + if (weight >= fWeightThreshold){ + if (fSplitEnteringParticles){ + G4String logicalVolumeNamePreStep = step->GetPreStepPoint()->GetPhysicalVolume()->GetLogicalVolume()->GetName(); + if (((fIsFirstStep) && (step->GetPreStepPoint()->GetStepStatus() ==1) && (logicalVolumeNamePreStep == fMotherVolumeName)) + || ((fIsFirstStep) && (track->GetLogicalVolumeAtVertex()->GetName() != logicalVolumeNamePreStep) && (track->GetLogicalVolumeAtVertex()->GetName() != fMotherVolumeName))) { + G4ThreeVector position = step->GetPreStepPoint()->GetPosition(); + G4ThreeVector momentum = step->GetPreStepPoint()->GetMomentum(); + G4double ekin = step->GetPreStepPoint()->GetKineticEnergy(); + + const G4DynamicParticle* particleType = track->GetDynamicParticle(); + G4double time = step->GetPreStepPoint()->GetGlobalTime(); + G4TrackVector *trackVector = step->GetfSecondary(); + + for (int i = 0; i < fSplittingFactor -1 ; i++) { + G4DynamicParticle* particleTypeToAdd = new G4DynamicParticle(*particleType); + G4Track* clone = new G4Track(particleTypeToAdd ,time,position); + clone->SetKineticEnergy(ekin); + clone->SetMomentumDirection(momentum); + clone->SetWeight( weight/fSplittingFactor); + trackVector->push_back(clone); + } + step->GetPreStepPoint()->SetWeight(weight/fSplittingFactor); + step->GetPostStepPoint()->SetWeight(weight/fSplittingFactor); + track->SetWeight(weight/fSplittingFactor); + + + } + } + + + if(fSplitExitingParticles){ + G4String logicalVolumeNamePostStep = step->GetPostStepPoint()->GetPhysicalVolume()->GetLogicalVolume()->GetName(); + if (std::find(fListOfVolumeAncestor.begin(), fListOfVolumeAncestor.end(),logicalVolumeNamePostStep) !=fListOfVolumeAncestor.end()){ + G4TrackVector *trackVector = step->GetfSecondary(); + for (int i = 0; i < fSplittingFactor-1; i++) { + G4Track* clone = new G4Track(*track); + clone->SetWeight( weight/fSplittingFactor); + trackVector->push_back(clone); + } + step->GetPostStepPoint()->SetWeight(weight/fSplittingFactor); + track->SetWeight(weight/fSplittingFactor); + } + } + + } + fIsFirstStep =false; +} diff --git a/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.h b/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.h new file mode 100644 index 000000000..871342f7c --- /dev/null +++ b/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.h @@ -0,0 +1,45 @@ +/* -------------------------------------------------- + Copyright (C): OpenGATE Collaboration + This software is distributed under the terms + of the GNU Lesser General Public Licence (LGPL) + See LICENSE.md for further details + -------------------------------------------------- */ + +#ifndef GateSurfaceSplittingActor_h +#define GateSurfaceSplittingActor_h + +#include "G4Cache.hh" +#include "GateVActor.h" +#include + +namespace py = pybind11; + +class GateSurfaceSplittingActor : public GateVActor { + +public: + // Constructor + GateSurfaceSplittingActor(py::dict &user_info); + + void ActorInitialize() override; + + void StartSimulationAction() override; + + // Main function called every step in attached volume + void SteppingAction(G4Step *) override; + + void PreUserTrackingAction(const G4Track *) override; + + + G4bool fSplitEnteringParticles =false; + G4bool fSplitExitingParticles =false ; + G4int fSplittingFactor; + G4bool fIsFirstStep; + G4bool fWeightThreshold; + G4String fMotherVolumeName; + std::vector fListOfVolumeAncestor; + + + long fNbOfKilledParticles{}; +}; + +#endif diff --git a/core/opengate_core/opengate_lib/pyGateSurfaceSplittingActor.cpp b/core/opengate_core/opengate_lib/pyGateSurfaceSplittingActor.cpp new file mode 100644 index 000000000..984e7a937 --- /dev/null +++ b/core/opengate_core/opengate_lib/pyGateSurfaceSplittingActor.cpp @@ -0,0 +1,19 @@ +/* -------------------------------------------------- + Copyright (C): OpenGATE Collaboration + This software is distributed under the terms + of the GNU Lesser General Public Licence (LGPL) + See LICENSE.md for further details + -------------------------------------------------- */ + +#include + +namespace py = pybind11; + +#include "GateSurfaceSplittingActor.h" + +void init_GateSurfaceSplittingActor(py::module &m) { + py::class_,GateVActor>(m, "GateSurfaceSplittingActor") + .def(py::init()) + .def_readwrite("fListOfVolumeAncestor",&GateSurfaceSplittingActor::fListOfVolumeAncestor) + .def(py::init()); +} diff --git a/opengate/actors/actorbuilders.py b/opengate/actors/actorbuilders.py index 1756e64c1..1ffc79547 100644 --- a/opengate/actors/actorbuilders.py +++ b/opengate/actors/actorbuilders.py @@ -17,6 +17,7 @@ SourceInfoActor, TestActor, KillActor, + SurfaceSplittingActor, ) from .dynamicactors import DynamicGeometryActor from ..utility import make_builders @@ -42,6 +43,7 @@ ARFTrainingDatasetActor, TestActor, KillActor, + SurfaceSplittingActor, DynamicGeometryActor, } actor_builders = make_builders(actor_type_names) diff --git a/opengate/actors/miscactors.py b/opengate/actors/miscactors.py index 5b12f1566..48f148fde 100644 --- a/opengate/actors/miscactors.py +++ b/opengate/actors/miscactors.py @@ -5,6 +5,7 @@ import numpy as np import time import platform +from anytree import Node, RenderTree import opengate_core as g4 from .base import ActorBase from ..exception import fatal @@ -427,3 +428,35 @@ def set_default_user_info(user_info): def __init__(self, user_info): ActorBase.__init__(self, user_info) g4.GateKillActor.__init__(self, user_info.__dict__) + +class SurfaceSplittingActor(g4.GateSurfaceSplittingActor, ActorBase): + type_name = "SurfaceSplittingActor" + + def set_default_user_info(user_info): + ActorBase.set_default_user_info(user_info) + user_info.list_of_volume_name = [] + user_info.splitting_factor = 1 + user_info.split_entering_particles = False + user_info.split_exiting_particles = False + user_info.weight_threshold = 0 + + def __init__(self, user_info): + ActorBase.__init__(self, user_info) + g4.GateSurfaceSplittingActor.__init__(self, user_info.__dict__) + self.list_of_volume_name = user_info.list_of_volume_name + self.user_info.mother = user_info.mother + + + def initialize(self, volume_engine=None): + + super().initialize(volume_engine) + volume_tree = self.simulation.volume_manager.get_volume_tree() + dico_of_volume_tree = {} + for pre, _, node in RenderTree(volume_tree): + dico_of_volume_tree[str(node.name)] = node + volume_name = self.user_info.mother + while volume_name != 'world': + node = dico_of_volume_tree[volume_name] + volume_name = node.mother + self.list_of_volume_name.append(volume_name) + self.fListOfVolumeAncestor = self.list_of_volume_name diff --git a/opengate/managers.py b/opengate/managers.py index 95d364fd4..332a8d488 100644 --- a/opengate/managers.py +++ b/opengate/managers.py @@ -887,6 +887,9 @@ def dump_volume_types(self): def dump_material_database_names(self): return list(self.material_database.filenames) + + def get_volume_tree(self): + return (self.volume_tree_root) def setter_hook_verbose_level(self, verbose_level): diff --git a/opengate/tests/src/test073_geometrical_splitting_volume_surface.py b/opengate/tests/src/test073_geometrical_splitting_volume_surface.py new file mode 100644 index 000000000..f3b2d8278 --- /dev/null +++ b/opengate/tests/src/test073_geometrical_splitting_volume_surface.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import opengate as gate +from opengate.tests import utility +from scipy.spatial.transform import Rotation +import numpy as np +from anytree import Node,RenderTree +import uproot + + +def test073(entry_data, exit_data, splitting_factor): + splitted_particle_data_entry = entry_data[entry_data["TrackCreatorProcess"] == "none"] + splitted_particle_data_exit = exit_data[exit_data["TrackCreatorProcess"] == "none"] + + array_weight_1 = splitted_particle_data_entry["Weight"] + array_weight_2 = splitted_particle_data_exit["Weight"] + + + if (np.round(np.sum(array_weight_1),3) == 1) and len(array_weight_1) == splitting_factor: + if (np.round(np.sum(array_weight_2),3) == 1) and len(array_weight_2) == splitting_factor: + return True + else : return False + else : return False + + +if __name__ == "__main__": + paths = utility.get_default_test_paths(__file__) + output_path = paths.output + + print(output_path) + # create the simulation + sim = gate.Simulation() + + # main options + ui = sim.user_info + ui.g4_verbose = False + ui.visu = True + ui.visu_type = "vrml" + ui.check_volumes_overlap = False + # ui.running_verbose_level = gate.logger.EVENT + ui.number_of_threads = 1 + ui.random_seed = "auto" + + # units + m = gate.g4_units.m + km = gate.g4_units.km + mm = gate.g4_units.mm + cm = gate.g4_units.cm + nm = gate.g4_units.nm + Bq = gate.g4_units.Bq + MeV = gate.g4_units.MeV + keV = gate.g4_units.keV + sec = gate.g4_units.s + gcm3 = gate.g4_units["g/cm3"] + + + # adapt world size + world = sim.world + world.size = [1 * m, 1 * m, 1 * m] + world.material = "G4_Galactic" + + big_box = sim.add_volume("Box","big_box") + big_box.mother = world.name + big_box.material = "G4_Galactic" + big_box.size = [0.8*m,0.8*m,0.8*m] + + actor_box = sim.add_volume("Box", "actor_box") + actor_box.mother = big_box.name + actor_box.material = "G4_Galactic" + actor_box.size = [0.6 * m, 0.6 * m, 0.6 * m] + actor_box.translation = [0,0,-0.1*m] + + + + + source_1 = sim.add_source("GenericSource", "elec_source_1") + source_1.particle = "e-" + source_1.position.type = "box" + source_1.mother = big_box.name + source_1.position.size = [1*cm,1*cm,1*cm] + source_1.position.translation = [0,0.35*m,0] + source_1.direction.type = "momentum" + source_1.direction.momentum = [0,-1,0] + source_1.energy.type = "mono" + source_1.energy.mono = 10 * MeV + source_1.n= 1 + + source_2 = sim.add_source("GenericSource", "elec_source_2") + source_2.particle = "e-" + source_2.position.type = "box" + source_2.mother = big_box.name + source_2.position.size = [1 * cm, 1 * cm, 1 * cm] + source_2.position.translation = [0, 0, -0.39 * m] + source_2.direction.type = "momentum" + source_2.direction.momentum = [0, 0, -1] + source_2.energy.type = "mono" + source_2.energy.mono = 10 * MeV + source_2.n = 1 + + + geom_splitting = sim.add_actor("SurfaceSplittingActor","splitting_act") + geom_splitting.mother = actor_box.name + geom_splitting.splitting_factor = 10 + geom_splitting.weight_threshold = 1 + geom_splitting.split_entering_particles = True + geom_splitting.split_exiting_particles = True + + + entry_phase_space = sim.add_volume("Box","entry_phase_space") + entry_phase_space.mother = actor_box + entry_phase_space.size = [0.6*m,1*nm,0.6*m] + entry_phase_space.material = "G4_Galactic" + entry_phase_space.translation = [0,0.3*m - 0.5*nm,0] + entry_phase_space.color = [0.5,0.9,0.3,1] + + exit_phase_space = sim.add_volume("Box", "exit_phase_space") + exit_phase_space.mother = world.name + exit_phase_space.size = [0.6 * m, 0.6 * m, 1 * nm] + exit_phase_space.material = "G4_Galactic" + exit_phase_space.translation = [0, 0, -0.4 * m - 1 * nm] + exit_phase_space.color = [0.5, 0.9, 0.3, 1] + + # # print(sim.volume_manager.dump_volume_tree()) + liste_phase_space_name = [entry_phase_space.name,exit_phase_space.name,] + for name in liste_phase_space_name: + + phsp = sim.add_actor("PhaseSpaceActor", "PhaseSpace_"+name) + phsp.mother = name + phsp.attributes = ["EventID","TrackID","Weight","PDGCode","TrackCreatorProcess"] + name_phsp = "test073_" +name+".root" + phsp.output = output_path / name_phsp + + + sim.physics_manager.physics_list_name = "G4EmStandardPhysics_option3" + sim.physics_manager.enable_decay = False + sim.physics_manager.global_production_cuts.gamma = 1 * mm + sim.physics_manager.global_production_cuts.electron = 1 * mm + sim.physics_manager.global_production_cuts.positron = 1 * mm + + + s = sim.add_actor("SimulationStatisticsActor", "Stats") + s.track_types_flag = True + + + # go ! + sim.run() + output = sim.output + stats = sim.output.get_actor("Stats") + print(stats) + + # + entry_phsp = uproot.open(str(output_path) + "/test073_" + liste_phase_space_name[0] + ".root" +":PhaseSpace_" + liste_phase_space_name[0]) + exit_phase_space = uproot.open(str(output_path) + "/test073_" + liste_phase_space_name[1] + ".root" + ":PhaseSpace_" + liste_phase_space_name[1]) + # + df_entry = entry_phsp.arrays() + df_exit = exit_phase_space.arrays() + # + is_ok = test073(df_entry, df_exit,geom_splitting.splitting_factor) + # + utility.test_ok(is_ok) \ No newline at end of file From 71e276da8607bc5eb47b8d345fb5da91f1f8dda7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 15:00:33 +0000 Subject: [PATCH 2/5] [pre-commit.ci] Automatic python and c++ formatting --- .../GateSurfaceSplittingActor.cpp | 84 +++++++++-------- .../opengate_lib/GateSurfaceSplittingActor.h | 6 +- .../pyGateSurfaceSplittingActor.cpp | 7 +- opengate/actors/miscactors.py | 8 +- opengate/managers.py | 4 +- ...73_geometrical_splitting_volume_surface.py | 93 ++++++++++++------- 6 files changed, 117 insertions(+), 85 deletions(-) diff --git a/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.cpp b/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.cpp index 53b88c804..1afbbf25d 100644 --- a/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.cpp +++ b/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.cpp @@ -6,28 +6,30 @@ ------------------------------------ -------------- */ #include "GateSurfaceSplittingActor.h" +#include "G4LogicalVolumeStore.hh" #include "G4ios.hh" #include "GateHelpers.h" #include "GateHelpersDict.h" -#include "G4LogicalVolumeStore.hh" GateSurfaceSplittingActor::GateSurfaceSplittingActor(py::dict &user_info) : GateVActor(user_info, false) { fActions.insert("StartSimulationAction"); fActions.insert("SteppingAction"); fActions.insert("PreUserTrackingAction"); - fMotherVolumeName = DictGetStr(user_info,"mother"); - fWeightThreshold = DictGetBool(user_info,"weight_threshold"); - fSplittingFactor = DictGetInt(user_info,"splitting_factor"); - fSplitEnteringParticles = DictGetBool(user_info,"split_entering_particles"); - fSplitExitingParticles = DictGetBool(user_info,"split_exiting_particles"); + fMotherVolumeName = DictGetStr(user_info, "mother"); + fWeightThreshold = DictGetBool(user_info, "weight_threshold"); + fSplittingFactor = DictGetInt(user_info, "splitting_factor"); + fSplitEnteringParticles = DictGetBool(user_info, "split_entering_particles"); + fSplitExitingParticles = DictGetBool(user_info, "split_exiting_particles"); } void GateSurfaceSplittingActor::ActorInitialize() {} -void GateSurfaceSplittingActor::StartSimulationAction() { fNbOfKilledParticles = 0; } +void GateSurfaceSplittingActor::StartSimulationAction() { + fNbOfKilledParticles = 0; +} -void GateSurfaceSplittingActor::PreUserTrackingAction(const G4Track* track){ +void GateSurfaceSplittingActor::PreUserTrackingAction(const G4Track *track) { fIsFirstStep = true; } @@ -36,51 +38,59 @@ void GateSurfaceSplittingActor::SteppingAction(G4Step *step) { auto track = step->GetTrack(); auto weight = track->GetWeight(); - - if (weight >= fWeightThreshold){ - if (fSplitEnteringParticles){ - G4String logicalVolumeNamePreStep = step->GetPreStepPoint()->GetPhysicalVolume()->GetLogicalVolume()->GetName(); - if (((fIsFirstStep) && (step->GetPreStepPoint()->GetStepStatus() ==1) && (logicalVolumeNamePreStep == fMotherVolumeName)) - || ((fIsFirstStep) && (track->GetLogicalVolumeAtVertex()->GetName() != logicalVolumeNamePreStep) && (track->GetLogicalVolumeAtVertex()->GetName() != fMotherVolumeName))) { + if (weight >= fWeightThreshold) { + if (fSplitEnteringParticles) { + G4String logicalVolumeNamePreStep = step->GetPreStepPoint() + ->GetPhysicalVolume() + ->GetLogicalVolume() + ->GetName(); + if (((fIsFirstStep) && (step->GetPreStepPoint()->GetStepStatus() == 1) && + (logicalVolumeNamePreStep == fMotherVolumeName)) || + ((fIsFirstStep) && + (track->GetLogicalVolumeAtVertex()->GetName() != + logicalVolumeNamePreStep) && + (track->GetLogicalVolumeAtVertex()->GetName() != + fMotherVolumeName))) { G4ThreeVector position = step->GetPreStepPoint()->GetPosition(); G4ThreeVector momentum = step->GetPreStepPoint()->GetMomentum(); G4double ekin = step->GetPreStepPoint()->GetKineticEnergy(); - - const G4DynamicParticle* particleType = track->GetDynamicParticle(); + + const G4DynamicParticle *particleType = track->GetDynamicParticle(); G4double time = step->GetPreStepPoint()->GetGlobalTime(); G4TrackVector *trackVector = step->GetfSecondary(); - - for (int i = 0; i < fSplittingFactor -1 ; i++) { - G4DynamicParticle* particleTypeToAdd = new G4DynamicParticle(*particleType); - G4Track* clone = new G4Track(particleTypeToAdd ,time,position); + + for (int i = 0; i < fSplittingFactor - 1; i++) { + G4DynamicParticle *particleTypeToAdd = + new G4DynamicParticle(*particleType); + G4Track *clone = new G4Track(particleTypeToAdd, time, position); clone->SetKineticEnergy(ekin); clone->SetMomentumDirection(momentum); - clone->SetWeight( weight/fSplittingFactor); + clone->SetWeight(weight / fSplittingFactor); trackVector->push_back(clone); } - step->GetPreStepPoint()->SetWeight(weight/fSplittingFactor); - step->GetPostStepPoint()->SetWeight(weight/fSplittingFactor); - track->SetWeight(weight/fSplittingFactor); - - + step->GetPreStepPoint()->SetWeight(weight / fSplittingFactor); + step->GetPostStepPoint()->SetWeight(weight / fSplittingFactor); + track->SetWeight(weight / fSplittingFactor); } } - - if(fSplitExitingParticles){ - G4String logicalVolumeNamePostStep = step->GetPostStepPoint()->GetPhysicalVolume()->GetLogicalVolume()->GetName(); - if (std::find(fListOfVolumeAncestor.begin(), fListOfVolumeAncestor.end(),logicalVolumeNamePostStep) !=fListOfVolumeAncestor.end()){ + if (fSplitExitingParticles) { + G4String logicalVolumeNamePostStep = step->GetPostStepPoint() + ->GetPhysicalVolume() + ->GetLogicalVolume() + ->GetName(); + if (std::find(fListOfVolumeAncestor.begin(), fListOfVolumeAncestor.end(), + logicalVolumeNamePostStep) != fListOfVolumeAncestor.end()) { G4TrackVector *trackVector = step->GetfSecondary(); - for (int i = 0; i < fSplittingFactor-1; i++) { - G4Track* clone = new G4Track(*track); - clone->SetWeight( weight/fSplittingFactor); + for (int i = 0; i < fSplittingFactor - 1; i++) { + G4Track *clone = new G4Track(*track); + clone->SetWeight(weight / fSplittingFactor); trackVector->push_back(clone); } - step->GetPostStepPoint()->SetWeight(weight/fSplittingFactor); - track->SetWeight(weight/fSplittingFactor); + step->GetPostStepPoint()->SetWeight(weight / fSplittingFactor); + track->SetWeight(weight / fSplittingFactor); } } - } - fIsFirstStep =false; + fIsFirstStep = false; } diff --git a/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.h b/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.h index 871342f7c..6adce44d1 100644 --- a/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.h +++ b/core/opengate_core/opengate_lib/GateSurfaceSplittingActor.h @@ -29,16 +29,14 @@ class GateSurfaceSplittingActor : public GateVActor { void PreUserTrackingAction(const G4Track *) override; - - G4bool fSplitEnteringParticles =false; - G4bool fSplitExitingParticles =false ; + G4bool fSplitEnteringParticles = false; + G4bool fSplitExitingParticles = false; G4int fSplittingFactor; G4bool fIsFirstStep; G4bool fWeightThreshold; G4String fMotherVolumeName; std::vector fListOfVolumeAncestor; - long fNbOfKilledParticles{}; }; diff --git a/core/opengate_core/opengate_lib/pyGateSurfaceSplittingActor.cpp b/core/opengate_core/opengate_lib/pyGateSurfaceSplittingActor.cpp index 984e7a937..0d6fc94e9 100644 --- a/core/opengate_core/opengate_lib/pyGateSurfaceSplittingActor.cpp +++ b/core/opengate_core/opengate_lib/pyGateSurfaceSplittingActor.cpp @@ -12,8 +12,11 @@ namespace py = pybind11; #include "GateSurfaceSplittingActor.h" void init_GateSurfaceSplittingActor(py::module &m) { - py::class_,GateVActor>(m, "GateSurfaceSplittingActor") + py::class_, + GateVActor>(m, "GateSurfaceSplittingActor") .def(py::init()) - .def_readwrite("fListOfVolumeAncestor",&GateSurfaceSplittingActor::fListOfVolumeAncestor) + .def_readwrite("fListOfVolumeAncestor", + &GateSurfaceSplittingActor::fListOfVolumeAncestor) .def(py::init()); } diff --git a/opengate/actors/miscactors.py b/opengate/actors/miscactors.py index 48f148fde..54ef398f8 100644 --- a/opengate/actors/miscactors.py +++ b/opengate/actors/miscactors.py @@ -428,7 +428,8 @@ def set_default_user_info(user_info): def __init__(self, user_info): ActorBase.__init__(self, user_info) g4.GateKillActor.__init__(self, user_info.__dict__) - + + class SurfaceSplittingActor(g4.GateSurfaceSplittingActor, ActorBase): type_name = "SurfaceSplittingActor" @@ -445,8 +446,7 @@ def __init__(self, user_info): g4.GateSurfaceSplittingActor.__init__(self, user_info.__dict__) self.list_of_volume_name = user_info.list_of_volume_name self.user_info.mother = user_info.mother - - + def initialize(self, volume_engine=None): super().initialize(volume_engine) @@ -455,7 +455,7 @@ def initialize(self, volume_engine=None): for pre, _, node in RenderTree(volume_tree): dico_of_volume_tree[str(node.name)] = node volume_name = self.user_info.mother - while volume_name != 'world': + while volume_name != "world": node = dico_of_volume_tree[volume_name] volume_name = node.mother self.list_of_volume_name.append(volume_name) diff --git a/opengate/managers.py b/opengate/managers.py index bf3fca344..910e3be10 100644 --- a/opengate/managers.py +++ b/opengate/managers.py @@ -889,9 +889,9 @@ def dump_volume_types(self): def dump_material_database_names(self): return list(self.material_database.filenames) - + def get_volume_tree(self): - return (self.volume_tree_root) + return self.volume_tree_root def setter_hook_verbose_level(self, verbose_level): diff --git a/opengate/tests/src/test073_geometrical_splitting_volume_surface.py b/opengate/tests/src/test073_geometrical_splitting_volume_surface.py index f3b2d8278..30ea10d67 100644 --- a/opengate/tests/src/test073_geometrical_splitting_volume_surface.py +++ b/opengate/tests/src/test073_geometrical_splitting_volume_surface.py @@ -5,23 +5,30 @@ from opengate.tests import utility from scipy.spatial.transform import Rotation import numpy as np -from anytree import Node,RenderTree +from anytree import Node, RenderTree import uproot def test073(entry_data, exit_data, splitting_factor): - splitted_particle_data_entry = entry_data[entry_data["TrackCreatorProcess"] == "none"] + splitted_particle_data_entry = entry_data[ + entry_data["TrackCreatorProcess"] == "none" + ] splitted_particle_data_exit = exit_data[exit_data["TrackCreatorProcess"] == "none"] array_weight_1 = splitted_particle_data_entry["Weight"] array_weight_2 = splitted_particle_data_exit["Weight"] - - if (np.round(np.sum(array_weight_1),3) == 1) and len(array_weight_1) == splitting_factor: - if (np.round(np.sum(array_weight_2),3) == 1) and len(array_weight_2) == splitting_factor: + if (np.round(np.sum(array_weight_1), 3) == 1) and len( + array_weight_1 + ) == splitting_factor: + if (np.round(np.sum(array_weight_2), 3) == 1) and len( + array_weight_2 + ) == splitting_factor: return True - else : return False - else : return False + else: + return False + else: + return False if __name__ == "__main__": @@ -54,37 +61,33 @@ def test073(entry_data, exit_data, splitting_factor): sec = gate.g4_units.s gcm3 = gate.g4_units["g/cm3"] - # adapt world size world = sim.world world.size = [1 * m, 1 * m, 1 * m] world.material = "G4_Galactic" - big_box = sim.add_volume("Box","big_box") + big_box = sim.add_volume("Box", "big_box") big_box.mother = world.name big_box.material = "G4_Galactic" - big_box.size = [0.8*m,0.8*m,0.8*m] + big_box.size = [0.8 * m, 0.8 * m, 0.8 * m] actor_box = sim.add_volume("Box", "actor_box") actor_box.mother = big_box.name actor_box.material = "G4_Galactic" actor_box.size = [0.6 * m, 0.6 * m, 0.6 * m] - actor_box.translation = [0,0,-0.1*m] - - - + actor_box.translation = [0, 0, -0.1 * m] source_1 = sim.add_source("GenericSource", "elec_source_1") source_1.particle = "e-" source_1.position.type = "box" source_1.mother = big_box.name - source_1.position.size = [1*cm,1*cm,1*cm] - source_1.position.translation = [0,0.35*m,0] + source_1.position.size = [1 * cm, 1 * cm, 1 * cm] + source_1.position.translation = [0, 0.35 * m, 0] source_1.direction.type = "momentum" - source_1.direction.momentum = [0,-1,0] + source_1.direction.momentum = [0, -1, 0] source_1.energy.type = "mono" source_1.energy.mono = 10 * MeV - source_1.n= 1 + source_1.n = 1 source_2 = sim.add_source("GenericSource", "elec_source_2") source_2.particle = "e-" @@ -98,21 +101,19 @@ def test073(entry_data, exit_data, splitting_factor): source_2.energy.mono = 10 * MeV source_2.n = 1 - - geom_splitting = sim.add_actor("SurfaceSplittingActor","splitting_act") + geom_splitting = sim.add_actor("SurfaceSplittingActor", "splitting_act") geom_splitting.mother = actor_box.name geom_splitting.splitting_factor = 10 geom_splitting.weight_threshold = 1 geom_splitting.split_entering_particles = True geom_splitting.split_exiting_particles = True - - entry_phase_space = sim.add_volume("Box","entry_phase_space") + entry_phase_space = sim.add_volume("Box", "entry_phase_space") entry_phase_space.mother = actor_box - entry_phase_space.size = [0.6*m,1*nm,0.6*m] + entry_phase_space.size = [0.6 * m, 1 * nm, 0.6 * m] entry_phase_space.material = "G4_Galactic" - entry_phase_space.translation = [0,0.3*m - 0.5*nm,0] - entry_phase_space.color = [0.5,0.9,0.3,1] + entry_phase_space.translation = [0, 0.3 * m - 0.5 * nm, 0] + entry_phase_space.color = [0.5, 0.9, 0.3, 1] exit_phase_space = sim.add_volume("Box", "exit_phase_space") exit_phase_space.mother = world.name @@ -122,27 +123,33 @@ def test073(entry_data, exit_data, splitting_factor): exit_phase_space.color = [0.5, 0.9, 0.3, 1] # # print(sim.volume_manager.dump_volume_tree()) - liste_phase_space_name = [entry_phase_space.name,exit_phase_space.name,] + liste_phase_space_name = [ + entry_phase_space.name, + exit_phase_space.name, + ] for name in liste_phase_space_name: - phsp = sim.add_actor("PhaseSpaceActor", "PhaseSpace_"+name) + phsp = sim.add_actor("PhaseSpaceActor", "PhaseSpace_" + name) phsp.mother = name - phsp.attributes = ["EventID","TrackID","Weight","PDGCode","TrackCreatorProcess"] - name_phsp = "test073_" +name+".root" + phsp.attributes = [ + "EventID", + "TrackID", + "Weight", + "PDGCode", + "TrackCreatorProcess", + ] + name_phsp = "test073_" + name + ".root" phsp.output = output_path / name_phsp - sim.physics_manager.physics_list_name = "G4EmStandardPhysics_option3" sim.physics_manager.enable_decay = False sim.physics_manager.global_production_cuts.gamma = 1 * mm sim.physics_manager.global_production_cuts.electron = 1 * mm sim.physics_manager.global_production_cuts.positron = 1 * mm - s = sim.add_actor("SimulationStatisticsActor", "Stats") s.track_types_flag = True - # go ! sim.run() output = sim.output @@ -150,12 +157,26 @@ def test073(entry_data, exit_data, splitting_factor): print(stats) # - entry_phsp = uproot.open(str(output_path) + "/test073_" + liste_phase_space_name[0] + ".root" +":PhaseSpace_" + liste_phase_space_name[0]) - exit_phase_space = uproot.open(str(output_path) + "/test073_" + liste_phase_space_name[1] + ".root" + ":PhaseSpace_" + liste_phase_space_name[1]) + entry_phsp = uproot.open( + str(output_path) + + "/test073_" + + liste_phase_space_name[0] + + ".root" + + ":PhaseSpace_" + + liste_phase_space_name[0] + ) + exit_phase_space = uproot.open( + str(output_path) + + "/test073_" + + liste_phase_space_name[1] + + ".root" + + ":PhaseSpace_" + + liste_phase_space_name[1] + ) # df_entry = entry_phsp.arrays() df_exit = exit_phase_space.arrays() # - is_ok = test073(df_entry, df_exit,geom_splitting.splitting_factor) + is_ok = test073(df_entry, df_exit, geom_splitting.splitting_factor) # - utility.test_ok(is_ok) \ No newline at end of file + utility.test_ok(is_ok) From 1483f92c07a3f8936e1e9f8c1dabb501092d1a87 Mon Sep 17 00:00:00 2001 From: majacquet Date: Wed, 20 Mar 2024 16:12:31 +0100 Subject: [PATCH 3/5] Update of the test name --- ... test075_geometrical_splitting_volume_surface.py} | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename opengate/tests/src/{test073_geometrical_splitting_volume_surface.py => test075_geometrical_splitting_volume_surface.py} (94%) diff --git a/opengate/tests/src/test073_geometrical_splitting_volume_surface.py b/opengate/tests/src/test075_geometrical_splitting_volume_surface.py similarity index 94% rename from opengate/tests/src/test073_geometrical_splitting_volume_surface.py rename to opengate/tests/src/test075_geometrical_splitting_volume_surface.py index f3b2d8278..5c7e044eb 100644 --- a/opengate/tests/src/test073_geometrical_splitting_volume_surface.py +++ b/opengate/tests/src/test075_geometrical_splitting_volume_surface.py @@ -9,7 +9,7 @@ import uproot -def test073(entry_data, exit_data, splitting_factor): +def test075(entry_data, exit_data, splitting_factor): splitted_particle_data_entry = entry_data[entry_data["TrackCreatorProcess"] == "none"] splitted_particle_data_exit = exit_data[exit_data["TrackCreatorProcess"] == "none"] @@ -35,7 +35,7 @@ def test073(entry_data, exit_data, splitting_factor): # main options ui = sim.user_info ui.g4_verbose = False - ui.visu = True + # ui.visu = True ui.visu_type = "vrml" ui.check_volumes_overlap = False # ui.running_verbose_level = gate.logger.EVENT @@ -128,7 +128,7 @@ def test073(entry_data, exit_data, splitting_factor): phsp = sim.add_actor("PhaseSpaceActor", "PhaseSpace_"+name) phsp.mother = name phsp.attributes = ["EventID","TrackID","Weight","PDGCode","TrackCreatorProcess"] - name_phsp = "test073_" +name+".root" + name_phsp = "test075_" +name+".root" phsp.output = output_path / name_phsp @@ -150,12 +150,12 @@ def test073(entry_data, exit_data, splitting_factor): print(stats) # - entry_phsp = uproot.open(str(output_path) + "/test073_" + liste_phase_space_name[0] + ".root" +":PhaseSpace_" + liste_phase_space_name[0]) - exit_phase_space = uproot.open(str(output_path) + "/test073_" + liste_phase_space_name[1] + ".root" + ":PhaseSpace_" + liste_phase_space_name[1]) + entry_phsp = uproot.open(str(output_path) + "/test075_" + liste_phase_space_name[0] + ".root" +":PhaseSpace_" + liste_phase_space_name[0]) + exit_phase_space = uproot.open(str(output_path) + "/test075_" + liste_phase_space_name[1] + ".root" + ":PhaseSpace_" + liste_phase_space_name[1]) # df_entry = entry_phsp.arrays() df_exit = exit_phase_space.arrays() # - is_ok = test073(df_entry, df_exit,geom_splitting.splitting_factor) + is_ok = test075(df_entry, df_exit,geom_splitting.splitting_factor) # utility.test_ok(is_ok) \ No newline at end of file From f9e8fd6f8d480dd3f82628f5a2d64ebeaf1f55c5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 15:17:07 +0000 Subject: [PATCH 4/5] [pre-commit.ci] Automatic python and c++ formatting --- ...75_geometrical_splitting_volume_surface.py | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/opengate/tests/src/test075_geometrical_splitting_volume_surface.py b/opengate/tests/src/test075_geometrical_splitting_volume_surface.py index 44a22ecc7..58af57f28 100644 --- a/opengate/tests/src/test075_geometrical_splitting_volume_surface.py +++ b/opengate/tests/src/test075_geometrical_splitting_volume_surface.py @@ -10,7 +10,9 @@ def test075(entry_data, exit_data, splitting_factor): - splitted_particle_data_entry = entry_data[entry_data["TrackCreatorProcess"] == "none"] + splitted_particle_data_entry = entry_data[ + entry_data["TrackCreatorProcess"] == "none" + ] splitted_particle_data_exit = exit_data[exit_data["TrackCreatorProcess"] == "none"] @@ -130,8 +132,14 @@ def test075(entry_data, exit_data, splitting_factor): phsp = sim.add_actor("PhaseSpaceActor", "PhaseSpace_" + name) phsp.mother = name - phsp.attributes = ["EventID","TrackID","Weight","PDGCode","TrackCreatorProcess"] - name_phsp = "test075_" +name+".root" + phsp.attributes = [ + "EventID", + "TrackID", + "Weight", + "PDGCode", + "TrackCreatorProcess", + ] + name_phsp = "test075_" + name + ".root" phsp.output = output_path / name_phsp sim.physics_manager.physics_list_name = "G4EmStandardPhysics_option3" @@ -150,14 +158,28 @@ def test075(entry_data, exit_data, splitting_factor): print(stats) # - entry_phsp = uproot.open(str(output_path) + "/test075_" + liste_phase_space_name[0] + ".root" +":PhaseSpace_" + liste_phase_space_name[0]) - exit_phase_space = uproot.open(str(output_path) + "/test075_" + liste_phase_space_name[1] + ".root" + ":PhaseSpace_" + liste_phase_space_name[1]) + entry_phsp = uproot.open( + str(output_path) + + "/test075_" + + liste_phase_space_name[0] + + ".root" + + ":PhaseSpace_" + + liste_phase_space_name[0] + ) + exit_phase_space = uproot.open( + str(output_path) + + "/test075_" + + liste_phase_space_name[1] + + ".root" + + ":PhaseSpace_" + + liste_phase_space_name[1] + ) # df_entry = entry_phsp.arrays() df_exit = exit_phase_space.arrays() # - is_ok = test075(df_entry, df_exit,geom_splitting.splitting_factor) - + is_ok = test075(df_entry, df_exit, geom_splitting.splitting_factor) + utility.test_ok(is_ok) From 8416cf443160c76c6d65d8c224839f62f71292a1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:57:07 +0000 Subject: [PATCH 5/5] [pre-commit.ci] Automatic python and c++ formatting --- opengate/actors/miscactors.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opengate/actors/miscactors.py b/opengate/actors/miscactors.py index eca7a7e98..1b77b908d 100644 --- a/opengate/actors/miscactors.py +++ b/opengate/actors/miscactors.py @@ -461,6 +461,7 @@ def initialize(self, volume_engine=None): self.list_of_volume_name.append(volume_name) self.fListOfVolumeAncestor = self.list_of_volume_name + """ class ComptonSplittingActor(g4.GateComptonSplittingActor,ActorBase): type_name = "ComptonSplittingActor"