-
Notifications
You must be signed in to change notification settings - Fork 27
Muon DIS with Pythia6 run through Geant4 #280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
a6fec0b
3d32a53
f128a66
877e6bd
36b336c
52c44a1
2c9636c
590ce52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having a separate projects that depends on one part of SNDSW and is a dependency of another is very confusing. Can we avoid this? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| cmake_minimum_required(VERSION 3.12) | ||
| project(G4Processes) | ||
|
|
||
| # Find GEANT4 and ROOT | ||
| find_package(Geant4 REQUIRED) | ||
| find_package(ROOT REQUIRED) | ||
|
|
||
| # Create library | ||
| add_library(G4Processes SHARED G4MuonDISProcess.cc G4MuonDISProcess.hh ${CMAKE_SOURCE_DIR}/shipgen/MuDISGenerator.cxx) | ||
|
|
||
| # Include headers, also from GEANT4 and ROOT | ||
| target_include_directories(G4Processes PUBLIC | ||
| ${CMAKE_CURRENT_SOURCE_DIR} | ||
| ${CMAKE_SOURCE_DIR}/shipgen | ||
| ${GEANT4_INCLUDE_DIR} | ||
| ${ROOT_INCLUDE_DIR} | ||
| ) | ||
|
|
||
| target_link_libraries(G4Processes PUBLIC | ||
| ${GEANT4_LIBRARIES} # Link GEANT4 libraries | ||
| ${ROOT_LIBRARIES} # Link ROOT libraries | ||
|
Comment on lines
+20
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably only link the necessary libraries. |
||
| ${ROOT_LIBRARY_DIR}/libEGPythia6.so | ||
| ${CMAKE_SOURCE_DIR}/shipgen # Link shipgen | ||
| ) | ||
|
|
||
| # Install the library | ||
| install(TARGETS G4Processes DESTINATION lib) | ||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| #pragma once | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be better to use the more standard include guards. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nevermind, you can just remove this, as you have the include guards already. |
||
|
|
||
| #ifndef G4MuonDISProcess_h | ||
| #define G4MuonDISProcess_h | ||
|
|
||
| #include "G4VDiscreteProcess.hh" | ||
| #include "G4Track.hh" | ||
| #include "G4Step.hh" | ||
| #include "G4ParticleDefinition.hh" | ||
| #include "G4VParticleChange.hh" | ||
| #include "G4ThreeVector.hh" | ||
| #include "globals.hh" | ||
| #include <tuple> | ||
| #include <vector> | ||
| #include <map> | ||
|
|
||
| class MuDISGenerator; | ||
| class G4Navigator; | ||
| class G4PhysicsFreeVector; | ||
|
|
||
| class G4MuonDISProcess : public G4VDiscreteProcess { | ||
| public: | ||
| /** Constructors **/ | ||
| G4MuonDISProcess(const G4String &name = "muonDIS"); | ||
| virtual ~G4MuonDISProcess() {} | ||
|
|
||
| /** Called to check if this process should apply to a given particle **/ | ||
| virtual G4bool IsApplicable(const G4ParticleDefinition &particle) override; | ||
|
|
||
| virtual G4double PostStepGetPhysicalInteractionLength(const G4Track &track, G4double previousStepSize, | ||
| G4ForceCondition *condition) override; | ||
|
|
||
| /** Called to calculate the mean free path **/ | ||
| virtual G4double | ||
| GetMeanFreePath(const G4Track &track, G4double previousStepSize, G4ForceCondition *condition) override; | ||
|
|
||
| /** Actual interaction **/ | ||
| virtual G4VParticleChange *PostStepDoIt(const G4Track &track, const G4Step &step) override; | ||
|
|
||
| /** Set the nucleon type **/ | ||
| void SetNucleonType(char *nucleon) { fNucleon = nucleon; } | ||
| /** Set the x-y-z range of the DIS interaction **/ | ||
| void SetRange(std::vector<float> *x_range, std::vector<float> *y_range, std::vector<float> *z_range); | ||
| /** Set the name of the geometry volume selected for placement of the DIS interaction **/ | ||
| void SetVolume(char* volume) { fVolumeName = volume; } | ||
| /** Set the DIS cross section lookup tables for the set nucleon type **/ | ||
| void SetCrossSectionTables(std::shared_ptr<std::map<int, G4PhysicsFreeVector*>> xsecTables) { fXsecTables = xsecTables; } | ||
|
|
||
| private: | ||
| /** Pythia6 call to generate the DIS process **/ | ||
| void SimulateDIS(const G4Track &track); | ||
|
|
||
| /** Reset private class member variables **/ | ||
| void ResetParameters(); | ||
|
|
||
| /** Rotation of Pythia6 outgoing particles to match physics CS **/ | ||
| std::tuple<double, double, double> | ||
| rotate(double ctheta, double stheta, double cphi, double sphi, double px, double py, double pz); | ||
|
|
||
| /*** 3D linear track extrapolation **/ | ||
| G4ThreeVector linear_track_extrapolation(G4ThreeVector pos, G4ThreeVector mom, G4double z_ref); | ||
|
|
||
| MuDISGenerator *disGen; /// class instance used to calculate material budget | ||
|
|
||
| G4Navigator *g4Navigator; /// Geant4 geo navigator | ||
|
|
||
| G4double fCrossSection; /// DIS cross section from the external generator | ||
| G4double fOutTracksWeight; /// Weight of outgoing particles | ||
| char *fNucleon; //! nucleon type | ||
| std::shared_ptr<std::map<int, G4PhysicsFreeVector*>> fXsecTables; /// DIS cross section lookup tables | ||
| char *fVolumeName; //! geometry volume name to place the DIS | ||
| G4double fXStart{}; /// start of x range to place the DIS | ||
| G4double fXEnd{}; /// end of x range to place the DIS | ||
| G4double fYStart{}; /// start of y range to place the DIS | ||
| G4double fYEnd{}; /// end of y range to place the DIS | ||
| G4double fZStart{}; /// start of z range to place the DIS | ||
| G4double fZEnd{}; /// end of z range to place the DIS | ||
| // The following are items that update on a per-event basis and not for each step! | ||
| G4bool was_simulated = 0; /// true if the DIS was already simulated, false otherwise | ||
| double bparam{}; /// mean density in a range | ||
| double mparam[8]{}; //[8] density parameters along track | ||
| double max_density{}; /// maximum density in the whole range | ||
| double prev_max_density{}; /// maximum density in the path traversed so far | ||
| double density_along_path{}; /// mean density in a range | ||
| double prev_start[3]{}; //[3] track position at previous step in the [z_start, z_end] range | ||
| }; | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,6 +48,15 @@ | |
| parser.add_argument('--zMax', type=float, help="max distance to apply energy cut", dest='zmax', default=70000.) | ||
| parser.add_argument("--Nuage", dest="nuage", help="Use Nuage, neutrino generator of OPERA", required=False, action="store_true") | ||
| parser.add_argument("--MuDIS", dest="mudis", help="Use muon deep inelastic scattering generator", required=False, action="store_true") | ||
|
|
||
| parser.add_argument("--MuDISG4", dest="mudisg4", help="Use external muon deep inelastic scattering generator with Geant4", required=False, action="store_true") | ||
| parser.add_argument('--nucleon', choices=['p+', 'n'], help='Type of nucleon') | ||
| parser.add_argument('--x_range', help='x position range placing muonDIS interaction as two values: start and end', type=float, nargs=2, default=[-1e10,1e10]) | ||
| parser.add_argument('--y_range', help='y position range placing muonDIS interaction as two values: start and end', type=float, nargs=2, default=[-1e10,1e10]) | ||
| parser.add_argument('--z_range', help='z position range placing muonDIS interaction as two values: start and end', type=float, nargs=2, default=[-1e10,1e10]) | ||
| parser.add_argument('--volume', help='Name of geometry volume where to simulate the DIS; e.g. volTarget, volMuUpstreamDet, volMuDownstreamDet, volVetoPlane, Wall', default="") | ||
| parser.add_argument('--dis_xsec_file', help='Name of DIS cross section file', default="/eos/experiment/sndlhc/MonteCarlo/Pythia6/MuonDIS/muDIScrossSec.root") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use the full path here. This will only work on lxplus or on systems where /eos/ is mounted via FUSE. |
||
|
|
||
| parser.add_argument("-n", "--nEvents",dest="nEvents", help="Number of events to generate", required=False, default=100, type=int) | ||
| parser.add_argument("-i", "--firstEvent",dest="firstEvent", help="First event of input file to use", required=False, default=0, type=int) | ||
| parser.add_argument("-s", "--seed",dest="theSeed", help="Seed for random number. Only for experts, see TRrandom::SetSeed documentation", required=False, default=0, type=int) | ||
|
|
@@ -67,6 +76,9 @@ | |
| # user hook | ||
| userTask = False | ||
|
|
||
| # make log colourful | ||
| ROOT.FairLogger.GetLogger().SetColoredLog(True) | ||
|
|
||
| class MyTask(ROOT.FairTask): | ||
| "user task" | ||
|
|
||
|
|
@@ -78,7 +90,9 @@ def Exec(self,opt): | |
| if MCTracks.GetEntries()>100: fMC.StopRun() | ||
|
|
||
| checking4overlaps = False | ||
| if options.debug: checking4overlaps = True | ||
| if options.debug: | ||
| checking4overlaps = True | ||
| ROOT.fair.Logger.SetConsoleSeverity("debug") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the difference between this and SetLogScreenLevel? I'd use the same method for both cases. Ideally right next to each other, so that it's easy to understand the logging behaviour. Maybe where you set the log to be colourful. |
||
|
|
||
| if options.pythia8: simEngine = "Pythia8" | ||
| if options.pg: simEngine = "PG" | ||
|
|
@@ -197,7 +211,8 @@ def Exec(self,opt): | |
| f'({options.EVx},{options.EVy},{options.EVz})[cm × cm × cm] \n' | ||
| f'with a uniform x-y spread of (Dx,Dy)=({options.Dx},{options.Dy})[cm × cm]' | ||
| f' and {options.nZSlices} z slices in steps of {options.zSliceStep}[cm].') | ||
| ROOT.FairLogger.GetLogger().SetLogScreenLevel("WARNING") # otherwise stupid printout for each event | ||
| if not options.debug: | ||
| ROOT.FairLogger.GetLogger().SetLogScreenLevel("WARNING") # otherwise stupid printout for each event | ||
| # -----muon DIS Background------------------------ | ||
| if simEngine == "muonDIS": | ||
| ut.checkFileExists(inputFile) | ||
|
|
@@ -294,6 +309,10 @@ def Exec(self,opt): | |
| elif 'Floor' in modules: | ||
| modules['Floor'].SetFastMuon() | ||
| modules['Floor'].SetZmax(options.zmax) | ||
| modules['Floor'].SetEmin(options.ecut) | ||
| if (options.ecut!=-1.): | ||
| print(f"Applying energy cut of {options.ecut} in full z range!\ | ||
| \nThe set zMax will be used for the FastMuon option only!") | ||
| print('transport only-muons up to z=',options.zmax) | ||
| # ------------------------------------------------------------------------ | ||
| #---Store the visualiztion info of the tracks, this make the output file very large!! | ||
|
|
@@ -305,6 +324,26 @@ def Exec(self,opt): | |
|
|
||
| # -----Initialize simulation run------------------------------------ | ||
| run.Init() | ||
|
|
||
| # -----muon DIS Background: add muonDIS from an external generator as a process in GEANT4 | ||
| # Only after Geant4 is initialized can one add a process to the simulation, | ||
| # thus one adds the custom DIS after run.Init() | ||
| if options.mudisg4: | ||
| # Make sure ranges run from lower to higher limit | ||
| options.x_range = sorted(options.x_range) | ||
| options.y_range = sorted(options.y_range) | ||
| options.z_range = sorted(options.z_range) | ||
| # add a process injector task for the Geant4 propagation | ||
| external_muDIS_injector = ROOT.MuonDISProcessInjector(options.nucleon, | ||
| options.x_range, | ||
| options.y_range, | ||
| options.z_range, | ||
| options.volume, | ||
| options.dis_xsec_file) | ||
| external_muDIS_injector.Init() | ||
| run.AddTask(external_muDIS_injector) | ||
| #------------------------------------------------------------------------ | ||
|
|
||
| gMC = ROOT.TVirtualMC.GetMC() | ||
| fStack = gMC.GetStack() | ||
| if MCTracksWithHitsOnly: | ||
|
|
@@ -379,7 +418,6 @@ def Exec(self,opt): | |
| procmu = gProcessTable.FindProcess(ROOT.G4String('muIoni'),ROOT.G4String('mu+')) | ||
| procmu.SetVerboseLevel(2) | ||
|
|
||
| if options.debug: ROOT.fair.Logger.SetConsoleSeverity("debug") | ||
| # -----Start run---------------------------------------------------- | ||
| run.Run(options.nEvents) | ||
| # -----Runtime database--------------------------------------------- | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this added here, if it is a separate project?