From fcd5eea56792b12d3609b8c37ff84d675a4e05d3 Mon Sep 17 00:00:00 2001 From: Kamil Sedlak Date: Mon, 18 May 2009 09:59:52 +0000 Subject: [PATCH] Kamil Sedlak 2009-05-18 This is the first version of the muSR simulation code (musrSim) based on the merged codes of Kamil Sedlak and Toni Shiroka. It should be a running version of the simulation code, however it has not been very well tested, therefore it will probably need some further development. --- GNUmakefile | 36 + doc/README_notes.txt | 45 + ...E_what_needs_to_be_changed_in_mac_file.txt | 210 +++ doc/dis04.cls | 518 ++++++++ doc/musrSim.pdf | Bin 0 -> 103193 bytes doc/musrSim.tex | 469 +++++++ include/BLEngeFunction.hh | 160 +++ include/F04ElementField.hh | 171 +++ include/F04FieldMessenger.hh | 73 + include/F04GlobalField.hh | 195 +++ include/MuDecayChannel.hh | 71 + include/MuDecayChannelWithSpin.hh | 130 ++ include/meyer.hh | 70 + include/musrDetectorConstruction.hh | 60 + include/musrDetectorMessenger.hh | 49 + include/musrErrorMessage.hh | 29 + include/musrEventAction.hh | 43 + include/musrMuFormation.hh | 80 ++ include/musrMuScatter.hh | 57 + include/musrMuonium.hh | 77 ++ include/musrParameters.hh | 44 + include/musrPhysicsList.hh | 52 + include/musrPrimaryGeneratorAction.hh | 108 ++ include/musrPrimaryGeneratorMessenger.hh | 46 + include/musrQuadrupole.hh | 49 + include/musrRootOutput.hh | 291 ++++ include/musrRunAction.hh | 36 + include/musrScintHit.hh | 139 ++ include/musrScintSD.hh | 38 + include/musrSteppingAction.hh | 73 + include/musrSteppingVerbose.hh | 26 + include/musrTabulatedElementField.hh | 68 + include/musrUniformField.hh | 45 + include/yields.hh | 44 + musrSim.cc | 151 +++ run/1050.mac | 812 ++++++++++++ ..._old_version_WILL_NOT_RUN_WITH_musrSim.mac | 697 ++++++++++ src/F04ElementField.cc | 200 +++ src/F04FieldMessenger.cc | 147 +++ src/F04GlobalField.cc | 330 +++++ src/G4DecayWithSpin.cc | 220 ++++ src/G4EqEMFieldWithSpin.cc | 177 +++ src/MuDecayChannel.cc | 202 +++ src/MuDecayChannelWithSpin.cc | 271 ++++ src/meyer.cc | 1032 +++++++++++++++ src/musrDetectorConstruction.cc | 1173 +++++++++++++++++ src/musrDetectorMessenger.cc | 168 +++ src/musrErrorMessage.cc | 62 + src/musrEventAction.cc | 92 ++ src/musrMuFormation.cc | 111 ++ src/musrMuScatter.cc | 86 ++ src/musrMuonium.cc | 112 ++ src/musrParameters.cc | 91 ++ src/musrPhysicsList.cc | 444 +++++++ src/musrPrimaryGeneratorAction.cc | 427 ++++++ src/musrPrimaryGeneratorMessenger.cc | 177 +++ src/musrQuadrupole.cc | 87 ++ src/musrRootOutput.cc | 446 +++++++ src/musrRunAction.cc | 100 ++ src/musrScintHit.cc | 156 +++ src/musrScintSD.cc | 359 +++++ src/musrSteppingAction.cc | 443 +++++++ src/musrSteppingVerbose.cc | 151 +++ src/musrTabulatedElementField.cc | 596 +++++++++ src/musrUniformField.cc | 91 ++ src/yields.cc | 107 ++ 66 files changed, 13320 insertions(+) create mode 100644 GNUmakefile create mode 100644 doc/README_notes.txt create mode 100644 doc/README_what_needs_to_be_changed_in_mac_file.txt create mode 100644 doc/dis04.cls create mode 100644 doc/musrSim.pdf create mode 100644 doc/musrSim.tex create mode 100644 include/BLEngeFunction.hh create mode 100644 include/F04ElementField.hh create mode 100644 include/F04FieldMessenger.hh create mode 100644 include/F04GlobalField.hh create mode 100644 include/MuDecayChannel.hh create mode 100644 include/MuDecayChannelWithSpin.hh create mode 100644 include/meyer.hh create mode 100644 include/musrDetectorConstruction.hh create mode 100644 include/musrDetectorMessenger.hh create mode 100644 include/musrErrorMessage.hh create mode 100644 include/musrEventAction.hh create mode 100644 include/musrMuFormation.hh create mode 100644 include/musrMuScatter.hh create mode 100644 include/musrMuonium.hh create mode 100644 include/musrParameters.hh create mode 100644 include/musrPhysicsList.hh create mode 100644 include/musrPrimaryGeneratorAction.hh create mode 100644 include/musrPrimaryGeneratorMessenger.hh create mode 100644 include/musrQuadrupole.hh create mode 100644 include/musrRootOutput.hh create mode 100644 include/musrRunAction.hh create mode 100644 include/musrScintHit.hh create mode 100644 include/musrScintSD.hh create mode 100644 include/musrSteppingAction.hh create mode 100644 include/musrSteppingVerbose.hh create mode 100644 include/musrTabulatedElementField.hh create mode 100644 include/musrUniformField.hh create mode 100644 include/yields.hh create mode 100644 musrSim.cc create mode 100644 run/1050.mac create mode 100644 run/1050_old_version_WILL_NOT_RUN_WITH_musrSim.mac create mode 100644 src/F04ElementField.cc create mode 100644 src/F04FieldMessenger.cc create mode 100644 src/F04GlobalField.cc create mode 100644 src/G4DecayWithSpin.cc create mode 100644 src/G4EqEMFieldWithSpin.cc create mode 100644 src/MuDecayChannel.cc create mode 100644 src/MuDecayChannelWithSpin.cc create mode 100644 src/meyer.cc create mode 100644 src/musrDetectorConstruction.cc create mode 100644 src/musrDetectorMessenger.cc create mode 100644 src/musrErrorMessage.cc create mode 100644 src/musrEventAction.cc create mode 100644 src/musrMuFormation.cc create mode 100644 src/musrMuScatter.cc create mode 100644 src/musrMuonium.cc create mode 100644 src/musrParameters.cc create mode 100644 src/musrPhysicsList.cc create mode 100644 src/musrPrimaryGeneratorAction.cc create mode 100644 src/musrPrimaryGeneratorMessenger.cc create mode 100644 src/musrQuadrupole.cc create mode 100644 src/musrRootOutput.cc create mode 100644 src/musrRunAction.cc create mode 100644 src/musrScintHit.cc create mode 100644 src/musrScintSD.cc create mode 100644 src/musrSteppingAction.cc create mode 100644 src/musrSteppingVerbose.cc create mode 100644 src/musrTabulatedElementField.cc create mode 100644 src/musrUniformField.cc create mode 100644 src/yields.cc diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..b95e65a --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,36 @@ +# $Id: GNUmakefile,v 1.2 2008/10/21 14:34:02 sedlak Exp $ +# -------------------------------------------------------------- +# GNUmakefile for examples module. Gabriele Cosmo, 06/04/98. +# -------------------------------------------------------------- + +name := musrSim +G4TARGET := $(name) +G4EXLIB := true +##LDFLAGS := $(shell root-config --glibs) +#ROOTLIBS := ${shell root-config --glibs} +#LDFLAGS := -L./ ${ROOTLIBS} + +# Root (exlude libNew and libpthread from library list) +#ROOTINC = -I$(ROOTSYS)/include + +ROOTLIBS = $(shell $(ROOTSYS)/bin/root-config --glibs) -lMinuit -lHtml +ROOTLIBS := $(filter-out -lNew,$(ROOTLIBS)) +#ROOTLIBS := $(filter-out -lpthread,$(ROOTLIBS)) +# +#ROOTLIBS := $(filter-out -lThread,$(ROOTLIBS)) +## ROOTLIBS := $(filter-out -lpthread,$(ROOTLIBS)) +#ROOTLIBS := $(filter-out -pthread,$(ROOTLIBS)) + +# Extra flags for G4 +#CPPFLAGS += $(ROOTINC) +#LDLIBS += $(ROOTLIBS) +EXTRALIBS += $(ROOTLIBS) +CPPFLAGS += -g +ifndef G4INSTALL + G4INSTALL = ../../.. +endif + +.PHONY: all +all: lib bin + +include $(G4INSTALL)/config/binmake.gmk diff --git a/doc/README_notes.txt b/doc/README_notes.txt new file mode 100644 index 0000000..d37b893 --- /dev/null +++ b/doc/README_notes.txt @@ -0,0 +1,45 @@ +SPECIAL SETTING SPECIFIED IN SOME FILES: + +=========================================================================== +1) ~/.bashrc file: + +The following lines were added to the ~/.bashrc file: + +export ROOTSYS="/usr/local/root/5.20.00" +export PATH=$ROOTSYS/bin:$PATH +if [ $LD_LIBRARY_PATH ] ; then +export LD_LIBRARY_PATH=$ROOTSYS/lib:$LD_LIBRARY_PATH +else +export LD_LIBRARY_PATH=$ROOTSYS/lib +fi +if [ $CPPFLAGS ] ; then +export CPPLFLAGS=-I$ROOTSYS/include:$CPPFLAGS +else +export CPPFLAGS=-I$ROOTSYS/include +fi +source /afs/psi.ch/user/s/sedlak/.alias + +=========================================================================== +2) /home/geant4/4.9.1.p03/env.sh file: + +Inside the "/home/geant4/4.9.1.p03/env.sh", the following lines were inserted +just before the last two lines " PATH=${PATH}:${G4WORKDIR}/bin/${G4SYSTEM} " and +" export PATH " : + +if [ $LD_LIBRARY_PATH ] ; then +LD_LIBRARY_PATH=${G4LIB}/${G4SYSTEM}:${CLHEP_BASE_DIR}/lib:${LD_LIBRARY_PATH} +export LD_LIBRARY_PATH +else +LD_LIBRARY_PATH=${G4LIB}/${G4SYSTEM}:${CLHEP_BASE_DIR}/lib +export LD_LIBRARY_PATH +fi +echo "On this machine the LD_LIBRARY_PATH=$LD_LIBRARY_PATH" + +=========================================================================== +3) ~/.alias file + +The following alias can be used to set-up the environment variables for Geant4: + +alias g4='export G4WORKDIR="/home/sedlak/bin_4.9.1.p03"; source /home/geant4/4.9.1.p03/env.sh; export G4VRMLFILE_VIEWER="vrmlview"; echo "On this machine the G4VRMLFILE_VIEWER=$G4VRMLFILE_VIEWER"' + +=========================================================================== diff --git a/doc/README_what_needs_to_be_changed_in_mac_file.txt b/doc/README_what_needs_to_be_changed_in_mac_file.txt new file mode 100644 index 0000000..613a1db --- /dev/null +++ b/doc/README_what_needs_to_be_changed_in_mac_file.txt @@ -0,0 +1,210 @@ +To migrate the steering (*.mac) file of Toni Shiroka to a stearing file that +runs with the new migrated version of "musrSim", do the following changes: + +1) replace all "lem4" by "musr", namely: + /lem4/command --> /musr/command + lem4/ScintSD --> musr/ScintSD + but do not change "lem4" in the name of the field map file, if such file exists (?) + +2) replace all "cones" by "cons" (This respects the naming convention of Geant4 solids "G4cons"): + /musr/command construct cones ---> /musr/command construct cons + +3) modify the lines where uniform magnetic field is defined: + old: /musr/command globalfield Trigg0_field 0. 0. -1149.15 uniform log_TriggE0 0 0 0 0 0 0.373 + new: /musr/command globalfield Trigg0_field 45 45 5 uniform 0. 0. -1149.15 log_TriggE0 0 0 0 0 0 0.373 + (the three coordinates which define the position of the centre of the field are shifted after the + keyword "uniform", and the three half-dimensions of the box, in which the field is being defined, are + specified before the keyword "uniform". These three coorinates (e.g. 45 45 5) are taken from the + definition of the logical volume (e.g. in our example from + /musr/command construct box TriggE0 45 45 5 G4_Galactic 0 0 -57.15 log_TriggerV norot dead 630 nofield ) + +4) Replace the way how physics processes are defined, i.e.: + Add: + +################################################################################### +######################### P H Y S I C S P R O C E S S E S ################## +################################################################################### +# --- Low Energy (default) --- +/musr/command process addDiscreteProcess gamma G4LowEnergyPhotoElectric +/musr/command process addDiscreteProcess gamma G4LowEnergyCompton +/musr/command process addDiscreteProcess gamma G4LowEnergyGammaConversion +/musr/command process addDiscreteProcess gamma G4LowEnergyRayleigh +/musr/command process addProcess e- G4MultipleScattering -1 1 1 +#/musr/command process addDiscreteProcess e- G4CoulombScattering +/musr/command process addProcess e- G4LowEnergyIonisation -1 2 2 +/musr/command process addProcess e- G4LowEnergyBremsstrahlung -1 -1 3 +/musr/command process addProcess e+ G4MultipleScattering -1 1 1 +#/musr/command process addDiscreteProcess e+ G4CoulombScattering +/musr/command process addProcess e+ G4eIonisation -1 2 2 +/musr/command process addProcess e+ G4eBremsstrahlung -1 3 3 +/musr/command process addProcess e+ G4eplusAnnihilation 0 -1 4 +# +# --- High Energy --- +#/musr/command process addDiscreteProcess gamma G4PhotoElectricEffect +#/musr/command process addDiscreteProcess gamma G4ComptonScattering +#/musr/command process addDiscreteProcess gamma G4GammaConversion +#/musr/command process addProcess e- G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e- G4CoulombScattering +#/musr/command process addProcess e- G4eIonisation -1 2 2 +#/musr/command process addProcess e- G4eBremsstrahlung -1 3 3 +#/musr/command process addProcess e+ G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e+ G4CoulombScattering +#/musr/command process addProcess e+ G4eIonisation -1 2 2 +#/musr/command process addProcess e+ G4eBremsstrahlung -1 3 3 +#/musr/command process addProcess e+ G4eplusAnnihilation 0 -1 4 +# +# --- Penelope --- +#/musr/command process addDiscreteProcess gamma G4PenelopePhotoElectric +#/musr/command process addDiscreteProcess gamma G4PenelopeCompton +#/musr/command process addDiscreteProcess gamma G4PenelopeGammaConversion +#/musr/command process addDiscreteProcess gamma G4PenelopeRayleigh +#/musr/command process addProcess e- G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e- G4CoulombScattering +#/musr/command process addProcess e- G4PenelopeIonisation -1 2 2 +#/musr/command process addProcess e- G4PenelopeBremsstrahlung -1 -1 3 +#/musr/command process addProcess e+ G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e+ G4CoulombScattering +#/musr/command process addProcess e+ G4PenelopeIonisation, -1 2 2 +#/musr/command process addProcess e+ G4PenelopeBremsstrahlung, -1 -1 3 +#/musr/command process addProcess e+ G4PenelopeAnnihilation, 0 -1 4 +# +# --- Muons --- +/musr/command process addProcess mu+ G4MultipleScattering -1 1 1 +#/musr/command process addProcess mu+ MultipleAndCoulombScattering -1 1 1 goulombRegion +#/musr/command process addDiscreteProcess mu+ G4CoulombScattering +/musr/command process addProcess mu+ G4MuIonisation -1 2 2 +/musr/command process addProcess mu+ G4MuBremsstrahlung -1 3 3 +/musr/command process addProcess mu+ G4MuPairProduction -1 4 4 +/musr/command process addProcess mu- G4MultipleScattering -1 1 1 +#/musr/command process addDiscreteProcess mu- G4CoulombScattering +/musr/command process addProcess mu- G4MuIonisation -1 2 2 +/musr/command process addProcess mu- G4MuBremsstrahlung -1 3 3 +/musr/command process addProcess mu- G4MuPairProduction -1 4 4 +# --- Muonium --- +/musr/command process addProcess mu+ musrMuFormation -1 -1 2 +#cks - the following line not supported yet, has to be tested (at the moment, musrMuScatter is hard wired in the musrPhysicsList.cc): +#/musr/command process addProcess Mu musrMuScatter -1 -1 1 + + + + And remove the obsolete "/musr/command typeofprocesses" : + +# Set processes from: lowenergy, penelope, coulombAndMultiple (default, Coul. only for CFoil), coulomb (for all, very slow). +/musr/command typeofprocesses coulombAndMultiple +#*/musr/command typeofprocesses penelope +#*/musr/command includeMuoniumProcesses false + + + +5) Replace "SetUserMinEkine": + + Old: + /musr/command SetUserMinEkine log_World 0.1 + + New (and more general): + #/musr/command SetUserLimits log_World ustepMax(mm) utrakMax(mm) utimeMax(ns) uekinMin(MeV) urangMin(mm) + /musr/command SetUserLimits log_World -1 -1 -1 1e-7 -1 + + + + Note: The old command + /musr/command SetUserLimits log_CFoil 1e-8 + should still be OK, but for safety reasons it might be better to replace it by + /musr/command SetUserLimits log_CFoil 1e-8 -1 -1 -1 -1 + + However!!! - this line was ignored in the old code (as one can see in the text output + of the simulation, so perhaps it should be commented out - such a small + step is probably danger to use! + + +6) Add the following lines to anable/disable the Root output variables: +################################################################################### +######################### R O O T O U T P U T ############################## +################################################################################### +#/musr/command rootOutput runID off +#/musr/command rootOutput eventID off +#/musr/command rootOutput weight off +#/musr/command rootOutput BFieldAtDecay off +#/musr/command rootOutput muIniPosX off +#/musr/command rootOutput muIniPosY off +#/musr/command rootOutput muIniPosZ off +#/musr/command rootOutput muIniMomX off +#/musr/command rootOutput muIniMomY off +#/musr/command rootOutput muIniMomZ off +#/musr/command rootOutput muIniPolX off +#/musr/command rootOutput muIniPolY off +#/musr/command rootOutput muIniPolZ off +#/musr/command rootOutput muDecayDetID off +#/musr/command rootOutput muDecayPosX off +#/musr/command rootOutput muDecayPosY off +#/musr/command rootOutput muDecayPosZ off +#/musr/command rootOutput muDecayTime off +#/musr/command rootOutput muDecayPolX off +#/musr/command rootOutput muDecayPolY off +#/musr/command rootOutput muDecayPolZ off +#/musr/command rootOutput muTargetTime off +#/musr/command rootOutput muTargetPolX off +#/musr/command rootOutput muTargetPolY off +#/musr/command rootOutput muTargetPolZ off +#/musr/command rootOutput muM0Time off +#/musr/command rootOutput muM0PolX off +#/musr/command rootOutput muM0PolY off +#/musr/command rootOutput muM0PolZ off +/musr/command rootOutput muM1Time off +/musr/command rootOutput muM1PolX off +/musr/command rootOutput muM1PolY off +/musr/command rootOutput muM1PolZ off +/musr/command rootOutput muM2Time off +/musr/command rootOutput muM2PolX off +/musr/command rootOutput muM2PolY off +/musr/command rootOutput muM2PolZ off +#/musr/command rootOutput posIniMomX off +#/musr/command rootOutput posIniMomY off +#/musr/command rootOutput posIniMomZ off +#/musr/command rootOutput fieldNomVal off +#/musr/command rootOutput det_ID off +#/musr/command rootOutput det_edep off +#/musr/command rootOutput det_edep_el off +#/musr/command rootOutput det_edep_pos off +#/musr/command rootOutput det_edep_gam off +#/musr/command rootOutput det_edep_mup off +#/musr/command rootOutput det_nsteps off +#/musr/command rootOutput det_length off +#/musr/command rootOutput det_start off +#/musr/command rootOutput det_end off +#/musr/command rootOutput det_x off +#/musr/command rootOutput det_y off +#/musr/command rootOutput det_z off +#/musr/command rootOutput det_kine off +/musr/command rootOutput det_VrtxKine off +/musr/command rootOutput det_VrtxX off +/musr/command rootOutput det_VrtxY off +/musr/command rootOutput det_VrtxZ off +/musr/command rootOutput det_VrtxVolID off +/musr/command rootOutput det_VrtxProcID off +/musr/command rootOutput det_VrtxTrackID off +/musr/command rootOutput det_VrtxParticleID off +/musr/command rootOutput det_VvvKine off +/musr/command rootOutput det_VvvX off +/musr/command rootOutput det_VvvY off +/musr/command rootOutput det_VvvZ off +/musr/command rootOutput det_VvvVolID off +/musr/command rootOutput det_VvvProcID off +/musr/command rootOutput det_VvvTrackID off +/musr/command rootOutput det_VvvParticleID off +### Root variables that are not written out by default, but can be switched on: +#/musr/command rootOutput fieldIntegralBx on +#/musr/command rootOutput fieldIntegralBy on +#/musr/command rootOutput fieldIntegralBz on +#/musr/command rootOutput fieldIntegralBz1 on +#/musr/command rootOutput fieldIntegralBz2 on +#/musr/command rootOutput fieldIntegralBz3 on + + + +7) Replace the (solid-name) keyword "trd" by "trd90y". + +8) Remove all keywords "nofield" at the end of the commands + " /musr/command construct ... " , since this does not have any meaning + any more (it had been used before we switched to "GlobalField"). + diff --git a/doc/dis04.cls b/doc/dis04.cls new file mode 100644 index 0000000..248db15 --- /dev/null +++ b/doc/dis04.cls @@ -0,0 +1,518 @@ +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesPackage{dis04}[2004/01/07 DIS'04 document class] +\newif\if@restonecol +\newif\if@titlepage +% +\DeclareOption{draft}{\setlength\overfullrule{5pt}} +\DeclareOption{final}{\setlength\overfullrule{0pt}} +\DeclareOption{twoside}{\@twosidetrue \@mparswitchtrue} +% +\ExecuteOptions{a4paper,10pt,twoside,final} +\ProcessOptions +% +%\def\publ{\hss \copyright ~Institute of Experimental Physics SAS, Ko\v sice, Slovakia\hss} +\def\publ{\hspace{10cm} } +% +\renewcommand\normalsize{% + \@setfontsize\normalsize\@xpt\@xiipt + \abovedisplayskip6\p@\@plus4\p@\@minus2\p@ + \abovedisplayshortskip\abovedisplayskip + \belowdisplayshortskip\abovedisplayshortskip + \belowdisplayskip\abovedisplayskip + \let\@listi\@listI} +\normalsize +\newcommand\small{% + \@setfontsize\small\@ixpt{11}% + \abovedisplayskip 8.5\p@ \@plus3\p@ \@minus4\p@ + \abovedisplayshortskip \z@ \@plus2\p@ + \belowdisplayshortskip 4\p@ \@plus2\p@ \@minus2\p@ + \def\@listi{\leftmargin\leftmargini + \topsep 4\p@ \@plus2\p@ \@minus2\p@ + \parsep 2\p@ \@plus\p@ \@minus\p@ + \itemsep \parsep}% + \belowdisplayskip \abovedisplayskip +} +\newcommand\footnotesize{% + \@setfontsize\footnotesize\@viiipt{9.5}% + \abovedisplayskip 6\p@ \@plus2\p@ \@minus4\p@ + \abovedisplayshortskip \z@ \@plus\p@ + \belowdisplayshortskip 3\p@ \@plus\p@ \@minus2\p@ + \def\@listi{\leftmargin\leftmargini + \topsep 3\p@ \@plus\p@ \@minus\p@ + \parsep 2\p@ \@plus\p@ \@minus\p@ + \itemsep \parsep}% + \belowdisplayskip \abovedisplayskip +} +\newcommand\scriptsize{\@setfontsize\scriptsize\@viipt\@viiipt} +\newcommand\tiny{\@setfontsize\tiny\@vpt\@vipt} +\newcommand\large{\@setfontsize\large\@xiipt{14}} +\newcommand\Large{\@setfontsize\Large\@xivpt{18}} +\newcommand\LARGE{\@setfontsize\LARGE\@xviipt{22}} +\newcommand\huge{\@setfontsize\huge\@xxpt{25}} +\newcommand\Huge{\@setfontsize\Huge\@xxvpt{30}} +\setlength\parindent{0.25in} +\setlength\smallskipamount{3\p@ \@plus 1\p@ \@minus 1\p@} +\setlength\medskipamount{6\p@ \@plus 2\p@ \@minus 2\p@} +\setlength\bigskipamount{12\p@ \@plus 4\p@ \@minus 4\p@} +%%%%%% +% +\newdimen\trimheight +\newdimen\trimwidth +\newdimen\typeheight +\newdimen\typewidth +\newdimen\tempdimen +\newdimen\normaltextheight +% + +\trimheight9.75in +\addtolength\trimheight{.047in} +\trimwidth6.50in +%cks \typeheight48.10pc +\typeheight60.pc +% +\setlength\parindent{1.5em}%10\p@ +\setlength\headheight{6\p@} +\setlength\headsep {15pt}%11 +\setlength\topskip {7\p@}%{10\p@} +\setlength\footskip{18pt} +\setlength\maxdepth{4\p@} +\setlength\@maxdepth\maxdepth +%cks \setlength\textwidth{30pc} +\setlength\textwidth{38pc} +\setlength\textheight\typeheight +\advance\textheight-\headheight +\advance\textheight-\headsep +%\advance\textheight\topskip%Comment +\advance\textheight-3pt %comment +\setlength\normaltextheight{\textheight} +%cks \setlength\oddsidemargin{60pt}%.625in% +%cks \setlength\evensidemargin{\trimwidth} +\setlength\oddsidemargin{0pt} +\setlength\evensidemargin{455pt} +\addtolength\evensidemargin{-\textwidth} +\addtolength\evensidemargin{-\oddsidemargin} +\setlength\marginparwidth{.75in} +\setlength\marginparsep{7\p@} +\setlength\marginparpush{5\p@} +%cks \setlength\topmargin{.65926in}% +\setlength\topmargin{0.in}% +\setlength\footnotesep{6\p@}%6pt +\setlength{\skip\footins}{11\p@ \@plus 5\p@ \@minus 2\p@} +\setlength\floatsep {18\p@ \@plus 2\p@ \@minus 2\p@} +\setlength\textfloatsep{20\p@ \@plus 2\p@ \@minus 4\p@} +\setlength\intextsep {18\p@ \@plus 2\p@ \@minus 2\p@} +\setlength\dblfloatsep {18\p@ \@plus 2\p@ \@minus 2\p@} +\setlength\dbltextfloatsep{20\p@ \@plus 2\p@ \@minus 4\p@} +\setlength\@fptop{0\p@} +\setlength\@fpsep{8\p@ \@plus 2fil} +\setlength\@fpbot{0\p@ \@plus 1fil} +\setlength\@dblfptop{0\p@ \@plus 1fil} +\setlength\@dblfpsep{8\p@ \@plus 2fil} +\setlength\@dblfpbot{0\p@ \@plus 1fil} +\setlength\partopsep{0\p@} +% +\setlength\lineskip{1\p@} +\setlength\normallineskip{1\p@}% +\renewcommand\baselinestretch{}%{} +\setlength\parskip{0\p@} +\@lowpenalty 51 +\@medpenalty 151 +\@highpenalty 301 +\@beginparpenalty -\@lowpenalty +\@endparpenalty -\@lowpenalty +\@itempenalty -\@lowpenalty +% +\def\@listi{\leftmargin\leftmargini + \parsep 4\p@ \@plus2\p@ \@minus\p@ + \topsep 8\p@ \@plus2\p@ \@minus4\p@ + \itemsep4\p@ \@plus2\p@ \@minus\p@} +\let\@listI\@listi +\@listi +\def\@listii {\leftmargin\leftmarginii + \labelwidth\leftmarginii + \advance\labelwidth-\labelsep + \topsep 4\p@ \@plus2\p@ \@minus\p@ + \parsep 2\p@ \@plus\p@ \@minus\p@ + \itemsep \parsep} +\def\@listiii{\leftmargin\leftmarginiii + \labelwidth\leftmarginiii + \advance\labelwidth-\labelsep + \topsep 2\p@ \@plus\p@\@minus\p@ + \parsep \z@ + \partopsep \p@ \@plus\z@ \@minus\p@ + \itemsep \topsep} +\def\@listiv {\leftmargin\leftmarginiv + \labelwidth\leftmarginiv + \advance\labelwidth-\labelsep} +\def\@listv {\leftmargin\leftmarginv + \labelwidth\leftmarginv + \advance\labelwidth-\labelsep} +\def\@listvi {\leftmargin\leftmarginvi + \labelwidth\leftmarginvi + \advance\labelwidth-\labelsep} +% +\setcounter{topnumber}{3} +\def\topfraction{.98} +\setcounter{bottomnumber}{3} +\def\bottomfraction{.98} +\setcounter{totalnumber}{6}%4 +\def\textfraction{.01} +\def\floatpagefraction{.98100} +\setcounter{dbltopnumber}{2} +\def\dbltopfraction{.981} +\def\dblfloatpagefraction{.99} +% +\newcounter {prvastrana} +% +\def\ps@myheadings{% +\def\@oddfoot{\ifnum\c@page=\c@prvastrana{ +\noindent{\small \publ}\rm\thepage} +\else{}\fi} + +\def\@evenfoot{\ifnum\c@page=\c@prvastrana{ +\noindent\rm\thepage{\small \publ}} +\else{}\fi} + +\def\@evenhead{% +\ifnum\c@page=\c@prvastrana{% +%Proceedings of the DIS'2004,~\v Strbsk\'e Pleso,~Slovakia~p.~\number\c@prvastrana -- \hfill +%Proceedings of the DIS'2004,~\v Strbsk\'e Pleso,~Slovakia\hfill +Internal PSI draft\hfill +} +\else{\thepage\hfill{\sl\runauthor}\qquad}\fi} + +\def\@oddhead{% +\ifnum\c@page=\c@prvastrana{% +%Proceedings of the DIS'2004,~\v Strbsk\'e Pleso,~Slovakia~p.~\number\c@prvastrana -- \hfill +%Proceedings of the DIS'2004,~\v Strbsk\'e Pleso,~Slovakia\hfill +Internal PSI draft\hfill +} +\else \qquad{\sl\shorttitle}\hfill\thepage\fi} +} +% +\newcommand\maketitle{\par + \begingroup + \renewcommand\thefootnote{\@fnsymbol\c@footnote}% + \def\@makefnmark{\rlap{\@textsuperscript{\normalfont\@thefnmark}}}% + \long\def\@makefntext##1{\parindent 1em\noindent + \hb@xt@1.8em{% + \hss\@textsuperscript{\normalfont\@thefnmark}}##1}% + \if@twocolumn + \ifnum \col@number=\@ne + \@maketitle + \else + \twocolumn[\@maketitle]% + \fi + \else + \newpage + \global\@topnum\z@ % Prevents figures from going at top of page. + \@maketitle + \fi +% \thispagestyle{plain} + \@thanks + \endgroup + \setcounter{footnote}{0}% + \setcounter{prvastrana}{\thepage} + \global\let\thanks\relax + \global\let\maketitle\relax + \global\let\@maketitle\relax + \global\let\@thanks\@empty + \global\let\@author\@empty + \global\let\@date\@empty + \global\let\@title\@empty + \global\let\title\relax + \global\let\author\relax + \global\let\date\relax + \global\let\and\relax +} +% +\def\title#1{\gdef\@title{\uppercase{#1}}} +\def\@title{\@latex@error{No \expand\title given}\@ehc} +%% +\def\@maketitle{% + \newpage + \null + \vskip 2em% +%\vspace*{-14pt} + \begin{center}% + \let \footnote \thanks + {\bf \@title \par}% + \vskip 2em% + \@aabuffer +\end{center}% + \par} +% \vskip 1.5em} +% +\def\@aabuffer{} +\def\author #1{\expandafter\def\expandafter\@aabuffer\expandafter + {\@aabuffer\small\rm\uppercase{#1}\relax\par + \vspace*{2pt}}}%\vspace{0.75em} +\def\address#1{\expandafter\def\expandafter\@aabuffer\expandafter + {\@aabuffer\small\it #1\relax\par + \vspace*{10pt}}} +% +\setcounter{secnumdepth}{2} +\newcounter {section} +\newcounter {subsection}[section] +\renewcommand\thesection {\@arabic\c@section} +\renewcommand\thesubsection {\thesection.\@arabic\c@subsection} +% +\newcommand\section{\@startsection {section}{1}{\z@}% + {-3.50ex \@plus -1ex \@minus -.2ex}% + {2.3ex \@plus.2ex}% + {\rightskip1pc plus1fil\normalfont\normalsize\bfseries}} +\newcommand\subsection{\@startsection{subsection}{2}{\z@}% + {-3.25ex\@plus -1ex \@minus -.2ex}% + {1.5ex \@plus .2ex}% + {\rightskip1pc plus1fil\normalfont\normalsize\it }} +% +\setlength\leftmargini {2em} +\leftmargin \leftmargini +\setlength\leftmarginii {2.2em} +\setlength\leftmarginiii {1.87em} +\setlength\leftmarginiv {1.7em} +\setlength\leftmarginv {.5em} +\setlength\leftmarginvi {.5em} +\setlength \labelsep {.5em} +\setlength \labelwidth{\leftmargini} +\addtolength\labelwidth{-\labelsep} +\@beginparpenalty -\@lowpenalty +\@endparpenalty -\@lowpenalty +\@itempenalty -\@lowpenalty +\renewcommand\theenumi{\@arabic\c@enumi} +\renewcommand\theenumii{\@alph\c@enumii} +\renewcommand\theenumiii{\@roman\c@enumiii} +\renewcommand\theenumiv{\@Alph\c@enumiv} +\newcommand\labelenumi{\theenumi.} +\newcommand\labelenumii{(\theenumii)} +\newcommand\labelenumiii{\theenumiii.} +\newcommand\labelenumiv{\theenumiv.} +\renewcommand\p@enumii{\theenumi} +\renewcommand\p@enumiii{\theenumi(\theenumii)} +\renewcommand\p@enumiv{\p@enumiii\theenumiii} +\newcommand\labelitemi{$\m@th\bullet$} +\newcommand\labelitemii{\normalfont\bfseries --} +\newcommand\labelitemiii{$\m@th\ast$} +\newcommand\labelitemiv{$\m@th\cdot$} +\newenvironment{description} + {\list{}{\labelwidth\z@ \itemindent-\leftmargin + \let\makelabel\descriptionlabel}} + {\endlist} +\newcommand*\descriptionlabel[1]{\hspace\labelsep + \normalfont\bfseries #1} +% + +\def\abstracts#1{ +\begin{center} +{\begin{minipage}{4.2truein} + \footnotesize + \parindent=0pt #1\par + \end{minipage}}\end{center} + \vskip 2em \par} + +\newenvironment{quotation} + {\list{}{\listparindent 1.5em% + \itemindent \listparindent + \rightmargin \leftmargin + \parsep \z@ \@plus\p@}% + \item\relax} + {\endlist} +% +\newenvironment{quote} + {\list{}{\rightmargin\leftmargin}% + \item\relax} + {\endlist} +% +%FOLLOWING THREE COMMANDS ARE FOR `LIST' COMMAND. +\topsep=0in +\parsep=0in +\itemsep=0in +% +\newcounter{arabiclistc} +\newenvironment{arabiclist} + {\setcounter{arabiclistc}{0} + \begin{list}{\arabic{arabiclistc}} + {\usecounter{arabiclistc} + \setlength{\parsep}{0pt} + \setlength{\itemsep}{0pt}}}{\end{list}} +% +%ACKNOWLEDGEMENT: this portion is from John Hershberger +% +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout + {\string\citation{#2}}\fi +\def\@citea{}\@cite{\@for\@citeb:=#2\do + {\@citea\def\@citea{,}\@ifundefined + {b@\@citeb}{{\bf ?}\@warning + {Citation `\@citeb' on page \thepage \space undefined}} + {\csname b@\@citeb\endcsname}}}{#1}} +% +\newif\if@cghi +\def\cite{\@cghitrue\@ifnextchar [{\@tempswatrue + \@citex}{\@tempswafalse\@citex[]}} +\def\citelow{\@cghifalse\@ifnextchar [{\@tempswatrue + \@citex}{\@tempswafalse\@citex[]}} +%\def\@cite#1#2{{$^{#1}$\if@tempswa\typeout +\def\@cite#1#2{{[#1]\if@tempswa\typeout + {Warning: optional citation argument ignored: `#2'} \fi}} +\newcommand{\citeup}{\cite} +% +\newcommand\appendix{\par + \setcounter{section}{0}% + \setcounter{subsection}{0}% + \renewcommand\thesection{\@Alph\c@section} + \section*{\appendixname}} +% +\setlength\arraycolsep{1.5\p@}%5pt +\setlength\tabcolsep{6\p@} +\setlength\arrayrulewidth{.4\p@} +\setlength\doublerulesep{2\p@} +\setlength\tabbingsep{\labelsep} +\skip\@mpfootins = \skip\footins +\setlength\fboxsep{3\p@} +\setlength\fboxrule{.4\p@} +\renewcommand\theequation{\@arabic\c@equation} +%% +\InputIfFileExists{psfig.sty}{}{} +\InputIfFileExists{epsf.sty}{}{} +\InputIfFileExists{epsfsafe.tex}{}{} +\InputIfFileExists{epsfig.sty}{}{} +% +\newcounter{figure} +\renewcommand\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +\def\fnum@figure{\figurename~\thefigure} +\newenvironment{figure} + {\@float{figure}} + {\end@float} +\newenvironment{figure*} + {\@dblfloat{figure}} + {\end@dblfloat} +% +\newcounter{table} +\renewcommand\thetable{\@arabic\c@table} +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\fnum@table{\tablename~\thetable} +\newenvironment{table} + {\@float{table}} + {\end@float} +\newenvironment{table*} + {\@dblfloat{table}} + {\end@dblfloat} +% +\newlength\abovecaptionskip +\newlength\belowcaptionskip +\setlength\abovecaptionskip{10\p@} +\setlength\belowcaptionskip{6\p@} +\def\captionfont{\normalfont\footnotesize{}} +\long\def\@makecaption#1#2{% + \captionfont + \vskip\abovecaptionskip + \sbox\@tempboxa{#1.\hskip.5em#2}% + \ifdim \wd\@tempboxa >\hsize + \noindent #1.\hskip.5em#2\par + \else + \global \@minipagefalse + \hb@xt@\hsize{\hfil\box\@tempboxa\hfil}% + \fi + \vskip\belowcaptionskip} +% +\def\figurebox#1#2#3{% + \def\arg{#3}% + \ifx\arg\empty + {\hfill\vbox{\hsize#2\hrule\hbox to #2{\vrule\hfill\vbox to #1{\hsize#2\vfill}\vrule}\hrule}\hfill}% + \else + {\hfill\epsfbox{#3}\hfill}% + \fi} +% +\def\@figurecaption#1#2{\unskip\vskip10pt{#1.\hskip.5em#2\par}} +% +\DeclareOldFontCommand{\rm}{\normalfont\rmfamily}{\mathrm} +\DeclareOldFontCommand{\sf}{\normalfont\sffamily}{\mathsf} +\DeclareOldFontCommand{\tt}{\normalfont\ttfamily}{\mathtt} +\DeclareOldFontCommand{\bf}{\normalfont\bfseries}{\mathbf} +\DeclareOldFontCommand{\it}{\normalfont\itshape}{\mathit} +\DeclareOldFontCommand{\sl}{\normalfont\slshape}{\@nomath\sl} +\DeclareOldFontCommand{\sc}{\normalfont\scshape}{\@nomath\sc} +\DeclareRobustCommand*\cal{\@fontswitch\relax\mathcal} +\DeclareRobustCommand*\mit{\@fontswitch\relax\mathnormal} +\newcommand\@pnumwidth{1.55em} +\newcommand\@tocrmarg{2.55em} +\newcommand\@dotsep{4.5} +% +\newenvironment{thebibliography}[1] + {\section*{\refname} + \begin{list}{\arabic{enumi}.} + {\usecounter{enumi}\setlength{\parsep}{0pt} + \setlength{\itemsep}{0pt} \settowidth + {\labelwidth}{#1.}\sloppy}}{\end{list}} +%% +\newenvironment{theindex} + {\if@twocolumn + \@restonecolfalse + \else + \@restonecoltrue + \fi + \columnseprule \z@ + \columnsep 35\p@ + \twocolumn[\section*{\indexname}]% + \@mkboth{\MakeUppercase\indexname}% + {\MakeUppercase\indexname}% + \thispagestyle{plain}\parindent\z@ + \parskip\z@ \@plus .3\p@\relax + \let\item\@idxitem} + {\if@restonecol\onecolumn\else\clearpage\fi} +\newcommand\@idxitem{\par\hangindent 40\p@} +\newcommand\subitem{\@idxitem \hspace*{20\p@}} +\newcommand\subsubitem{\@idxitem \hspace*{30\p@}} +\newcommand\indexspace{\par \vskip 10\p@ \@plus5\p@ \@minus3\p@\relax} +% +\renewcommand\footnoterule{% + \kern-3\p@ + \hrule\@width.4\columnwidth + \kern2.6\p@} +\newcommand\@makefntext[1]{% + \parindent 1em% + \noindent + \@makefnmark#1} +% +\def\thefootnote{\alph{footnote}} +\def\@makefnmark{{$^{\@thefnmark}$}} +% +\newcommand\contentsname{Contents} +\newcommand\listfigurename{List of Figures} +\newcommand\listtablename{List of Tables} +\newcommand\refname{References} +\newcommand\indexname{Index} +\newcommand\figurename{Figure} +\newcommand\tablename{Table} +\newcommand\partname{Part} +\newcommand\appendixname{Appendix} +\newcommand\abstractname{Abstract} +% +% +\bibliographystyle{unsrt} +\arraycolsep1.5pt +% +%%%%%%%%%%%%%%%% +% +\setlength\columnsep{0.25in} +\setlength\columnseprule{0\p@} + +\pagestyle{myheadings} +\pagenumbering{arabic} +\flushbottom +\def\sloppy{\tolerance=100000\hfuzz=\maxdimen\vfuzz=\maxdimen} +\vbadness=12000 +\hbadness=12000 +\sloppy +\onecolumn +\endinput +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% End %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + diff --git a/doc/musrSim.pdf b/doc/musrSim.pdf new file mode 100644 index 0000000000000000000000000000000000000000..87d0cb9ebcaf11d970d4025ba80f70a4947eb0a9 GIT binary patch literal 103193 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%0DUY%k>`lyd$xfP4fszc{3XJP+$OOJ?q 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 literal 0 HcmV?d00001 diff --git a/doc/musrSim.tex b/doc/musrSim.tex new file mode 100644 index 0000000..9b76509 --- /dev/null +++ b/doc/musrSim.tex @@ -0,0 +1,469 @@ +\documentclass[twoside]{dis04} +%\def\runauthor{Kamil Sedl\'{a}k} +\def\runauthor{PSI} +% for the H1 collaboration} +\def\shorttitle{musrSim} +\begin{document} + +%\newcommand{\xgmy}{\ensuremath{x^{\mathrm{jets}}_\gamma} } +%\newcommand{\GeV}{\ensuremath{\mathrm{GeV}} } +%\newcommand{\pb}{\ensuremath{\mathrm{pb}} } +%\newcommand{\gevsq}{\ensuremath{\mathrm{GeV}^2} } +%\newcommand{\Etone}{\ensuremath{E^*_{T\, 1}} } +%\newcommand{\Ettwo}{\ensuremath{E^*_{T\, 2}} } +%\newcommand{\Etmy}{\ensuremath{E^*_T} } +%\newcommand{\etaone}{\ensuremath{\eta^*_{1}} } +%\newcommand{\etatwo}{\ensuremath{\eta^*_{2}} } +%\newcommand{\etamy}{\ensuremath{\eta^*} } +%\newcommand{\ycut}{\ensuremath{y_c} } +\newcommand{\musr}{\ensuremath{\mu}SR} + +\title{Manual of musrSim} +%\title{GEANT Simulation Program for the +%$\mathbf{\mu}$SR Instruments} + +\author{Kamil Sedl\'ak and Toni Shiroka PSI} + +%\address{{\rm (on behalf of the H1 collaboration)}\\ +%Institute of Physics AS\,CR\\ +%%Academy of Sciences of the Czech Republic +%Na Slovance 2, 182 21 Praha 8, Czech Republic\\ +%E-mail: ksedlak@fzu.cz} + +\maketitle + +\abstracts{ +The program ``musrSim'' is a simulation program based on Geant4 +optimised for the $\mu$SR instruments. +This document describes some of the commands used in the user macros +of the simulation program for the $\mu$SR instruments based on the {\sc +Geant4}. The root output variables are also described. +} + + +\section{Initial muon parameters} + +\begin{description} +\item{\bf /gun/vertex \emph{x0} \emph{y0} \emph{z0} \emph{unit}}\\ + (default: /gun/vertex 0 0 -100 mm) \\ + Set mean values of the $x$, $y$ and $z$ coordinates of the generated particles (muons). + The smearing around these mean values instead is set by /gun/vertexsigma and + restricted by /gun/vertexboundary (see below).\\ + (Applicable also to TURTLE input). + +\item{\bf /gun/vertexsigma \emph{xSigma} \emph{ySigma} \emph{zSigma} \emph{unit}}\\ + (default: /gun/vertexsigma 0 0 0 mm) \\ + If {\it xSigma} $>0$ ... set $\sigma$, i.e. the standard deviation (RMS), of the $x$ coordinate + of the generated particles (muons) to $\sigma=xSigma$. The $x$ coordinate of the initial + muon is then generated according to the Gaussian distribution with the mean value of $x0$ + and the standard deviation of {\it xSigma}. \\ + If {\it xSigma} $<0$ ... the $x$ coordinate of the initial + muon is generated {\bf uniformly} in the interval of ($x0-$ {\it xSigma}, $x0+$ {\it xSigma}).\\ + If {\it xSigma} $= 0$ ... no smearing on the $x$ coordinate is applied.\\ + Similar is true for {\it ySigma} and {\it zSigma}. \\ + This variables are ignored when TURTLE input is requested. + +\item{\bf /gun/vertexboundary \emph{R\_max} \emph{z\_min} \emph{z\_max} \emph{unit}}\\ + Set maximum allowed radius, and minimum and maximum z coordinate of the generated particles (muons). + This command might be useful especially if the user wants to restrict the + area, in which initial particles are created, e.g.\ to force the initial muons + to be created inside the beam pipe. + + If the particles (muons) are read in from an external TURTLE file, + only the restriction on the maximum radius \emph{R\_max} + is applied on the initial particles, while \emph{z\_min} and \emph{z\_max} are ignored. + +\item{\bf /gun/kenergy \emph{kineticEnergy} \emph{unit}}\\ + Set the mean kinetic energy of the initial particles (muons). + +\item{\bf /gun/momentum \emph{momentum} \emph{unit}}\\ + Set the mean momentum of the initial particles (muons). + +\item{\bf /gun/momentumsmearing \emph{momentumSigma} \emph{unit}}\\ + Set $\sigma$, i.e. the standard deviation (RMS), of the momentum spread, which + is aplied randomly to each generated initial particle (muon). It is the magnitude + of the momentum, which is smeared. \\ + (Ignored by the TURTLE input. However, + a similar command ``/gun/turtleMomentumBite'' can be used for the TURTLE input file.) + +\item{\bf /gun/momentumboundary \emph{p\_min} \emph{p\_max} \emph{dummy} \emph{unit}}\\ + Set a boundary for the minimum and maximum momentum of the initial particles (muons). + The third argument \emph{dummy} is ignored.\\ + (Presently ignored by the TURTLE input). + +\item{\bf /gun/tilt \emph{xangle0} \emph{yangle0} \emph{dummy} \emph{unit}}\\ + The ``beam tilt'' is understood as a constant angle tilt that is applied to + all initial particles (muons) regardless on their distance from the centre of the beam.\\ + (Applicable also to TURTLE input). + +\item{\bf /gun/tiltsigma \emph{xangleSigma} \emph{yangleSigma} \emph{dummy} \emph{unit}}\\ + Gaussian smearing of the tilt angle.\\ + (Presently ignored by the TURTLE input). + +\item{\bf /gun/pitch \emph{pitch} \emph{unit}}\\ + The ``beam pitch'' is understood as a variable angle applied to the initial particles + (muons), which is directly proportional to the distance from the beam axis. + The particles closer to the beam axis become smaller pitch than particles further away + from the beam axis. + The angle given as \emph{pitch} will be applied to a particle generated 1\,mm away from the + beam centre, i.e. the particle generated 7\,mm away from the beam axis will be assigned + the angle of $7\cdot pitch$. + The pitch allows the user to focus or defocuse the initial particle + beam. Particles will be focused for positive pitch and defocused for the negative pitch.\\ + (Applicable also to TURTLE input). + +\item{\bf /gun/muonPolarizVector \emph{xpolaris} \emph{ypolaris} \emph{zpolaris}}\\ + Set polarisation of the initial particle (muon) in a form of a vector + $P=(xpolaris,ypolaris,zpolaris)$. The polarisation vector does not have to be normalised, + the normalisation will be done internally by the program. + However note that if the magnitude of P is set to less than 1e-8, the user can + achieve an unpolarised muon beam. See the source code of musrPrimaryGeneratorAction.cc + if you need to use unpolarised beam by this parameter, because there is some trick + based on the magnitude of P.\\ + (Applicable also to TURTLE input). + +\item{\bf /gun/muonPolarizFraction \emph{polarisFraction}}\\ + Set the fraction of the muon polarisation. The variable \emph{polarisFraction} + has to be set in the range of -1 to 1. \\ + If \emph{polarisFraction} is set to 1, all muons are polarised in the direction + of polarisation vector defined by ``/gun/muonPolarizVector''.\\ + If \emph{polarisFraction} is set to 0, half of the muons are polarised in the direction + of polarisation vector, the second half is polarised in the oposite dirrection, so + in the end the muon beam should act as unpolarised.\\ + If \emph{polarisFraction} is set to -1, all muons are polarised in the direction + oposite to the polarisation vector.\\ + {\bf If \emph{polarisFraction} is set to 0.9, then 95\% of the muons is polarised + in in the direction of polarisation vector, and 5\% of them is polarised in the + oposite dirrection!}.\\ + {\bf This command is ignored if magnitude of polarisation vector defined by + ``/gun/muonPolarizVector'' is smaller than 1e-8!} \\ + (Applicable also to TURTLE input). + +\item{\bf /gun/decaytimelimits \emph{muDecayTimeMin} \emph{muDecayTimeMax} \emph{muMeanLife} \emph{unit}}\\ + (default: /gun/decaytimelimits $-1$ $-1$ 2197.03\,ns ) \\ + If {\it muDecayTimeMax} is less or equal to zero, this command is ignored, + and the muon decay time is set internally by {\sc Geant4}. + Otherwise the muon will be forced to decay within a time interval given by + {\it muDecayTimeMin} and {\it muDecayTimeMax}, and the mean muon lifetime will + be set to {\it muMeanLife}. In such case {\it muDecayTimeMin} + has to be equal or larger than 0 and {\it muDecayTimeMax} has to be + larger {\bf or equal} to {\it muDecayTimeMin}.\\ + (Applicable also to TURTLE input). + +\item{\bf /gun/turtlefilename \emph{turtleFileName}}\\ + Set the filename of the TURTLE input file. If this varialble is set, TURTLE file + will be used to initiate muons. Otherwise the mouns would be generated randomly. + +\item{\bf /gun/turtleZ0position \emph{z0\_InitialTurtle} \emph{unit}}\\ + Set the z-position which has been used to generate the TURTLE file.\\ + If this value differes from the $z0$ value of the ``/gun/vertex'' command, + than the particle initial position is extrapolated from $z0\_InitialTurtle$ + to the point corresponding to $z0$, using the direction of its momenta.\\ + MORE DETAILS:\\ + When running TURTLE (e.g. when generating the TURTLE file using the TURTLE program), + the user has to specify the $z$ position, at which the TURTLE particles (muons) would be exported. + Sometimes this $z$ position does not correspond to the point of origin of the musrSim + geometry. In such case, the variable \emph{z0\_InitialTurtle} should be set to the + value, that in musrSim coordinate system corresponds to the point, at which the TURTLE + file was exported. For example -- if the TURTLE file was exported just after the last + quadrupole of a beam-pipe, and in the simulation the edge of the last quadrupole corresponds + to 100\,cm, than the \emph{z0\_InitialTurtle} should be also set to 100\,cm.\\ + +\item{\bf /gun/turtleMomentumBite \emph{turtleMomentumP0} \emph{turtleSmearingFactor} \emph{dummy} }\\ + Modify the smearing of the momentum bite specified in the TURTLE input file. + Normally the muon momentum is defined already in the turtle input file. This command allows the user + to modify the momentum smearing (momentum bite) of the muon beam. + The variable \emph{turtleMomentumP0} will be taken as the mean momentum (in MeV/c), around which + the momentum will be increased/decreased. It does not have to be the real mean value of the initial muon momentum distribution. + The variable \emph{turtleSmearingFactor} is the smearing factor in per cent, by which the momentum bite + will be increased/decreased around the \emph{turtleMomentumP0}. The following equation is used to change the + muon momentum: $p^{new}$ = {\it turtleMomentumP0} - ({\it turtleMomentumP0}-$p^{TURTLE}$)$\cdot$0.01$\cdot${\it turtleSmearingFactor}.\\ + This means that:\\ + {\it turtleSmearingFactor} = 100 ... the muon beam momentum will not be modified.\\ + {\it turtleSmearingFactor} = 0 ~~... the muon beam momentum will be set to the constant value of {\it turtleMomentumP0}.\\ + {\it turtleSmearingFactor} = 200 ... the muon beam will have two times broader distribution compared to the original TURTLE file. + +\item{\bf /gun/turtleFirstEventNr \emph{lineNumberOfTurtleFile} }\\ + +\end{description} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Detector construction} + +\begin{description} +% +\item{\bf /musr/command rotation \emph{matrixName} $\alpha$ $\beta$ $\gamma$} \\ + {\bf /musr/command rotation \emph{matrixName} \emph{vx} \emph{vy} \emph{vz} \emph{angle}}\\ + These commands define a rotation matrix of the name ``matrixName'' that can be used later on + during the definition of the detector geometry (see command ``/musr/command construct''). + It can be defined either by the Euler angles (if there are three float parameters behind the + \emph{matrixName}) or by the vector \emph{(vx,vy,vz)} and an \emph{angle} of rotation around this + vector (if the fourth float parameter behind the \emph{matrixName} is non-zero). + All angles are specified in degrees. +% +\item{\bf /musr/command construct \emph{solid}=string \emph{name}=string \emph{dimensions}=float ... \emph{material}=string + \emph{x}=float \emph{y}=float \emph{z}=float \emph{motherVolume}=string \emph{rotationMatrix}=string + \emph{sensitiveClass}=string \emph{idNumber}=int }\\ + This command defines a volume in {\sc Geant4} (It comprises three steps of {\sc Geant4}: defines a solid, + logical volume and physical volume. More details have to be found in {\sc Geant4} manual). \\ + \begin{itemize} + \item \emph{solid} can be one of the G4VSolid.cc particular types, presently ``tubs'', ``box'', ``sphere'', + or it can be one of the specifically implemented solids by our program as ``uprofile'' + (an U-profiled bar), ``alcSupportPlate'' (shape specific to ALC support plate), ``tubsbox'' + (a tube with a rectangular hole along its axis) and "tubsboxsegm" + (a volume that looks like an intersection of tube and box). Not all G4VSolids are + presently supported, but it is relatively easy to implement a new kind of solids + in the musrDetectorConstruction.cc class. + \item \emph{name} stands for the name of the volume. As the ``/musr/command construct'' construct + three kinds of classes (volumes) -- the solid, logical volume and physical + volume -- there are three names of the concrete volume used internally inside + the program: sol\_\emph{name}, log\_\emph{name} and phys\_\emph{name}. + The main volume, inside which all other volumes are positioned, has to be called ``World''. + \item \emph{dimensions} define the size of the required solid. They are kept equivalent to the + dimensions of solids as used in {\sc Geant4}. For example the ``box'' is defined + by its halfwidths along $x$, $y$ and $z$ coordinates. Note that the number of + \emph{dimensions} varies for each type of solid. + \item \emph{material} one of the materials defined in {\sc Geant4}, namely in the file + \$G4INSTALL/source/materials/src/G4NistMaterialBuilder.cc (e.g. ``G4\_Galactic'' for + vacuum, ``G4\_Cu'' for copper, ``G4\_AIR'' for air and + ``G4\_PLASTIC\_SC\_VINYLTOLUENE'' for a scintillator). + One can also define a new material inside the function + musrDetectorConstruction::DefineMaterials(). Presently ``Mylar'', ``Brass'' + and ``Steel'' are defined there. + \item \emph{x, y, z} -- coordinates of the volume, used to position the volume within + its mother volume (as used by the G4PVPlacement). + \item \emph{motherVolume} -- name of the mother volume, in which the given volume should be + positioned. Note that the mother volume has to be defined first (before its + daughter), and that the name of mother starts with a string {\bf log\_}\emph{name}, + following the naming convention defined above. + When the ``World'' volume is defined, its \emph{motherVolume} should be set to ``no\_logical\_volume''. + \item \emph{rotationMatrix} -- name of the rotation matrix that will be used to position + the volume inside its mother volume (as used in member function G4PVPlacement()). + Use string ``norot'' if no rotation is required for the given volume. + Otherwise the rotation matrix has to be defined by the command line + ``/musr/command rotation'' {\bf before} the given is defined. + \item \emph{sensitiveClass} -- specifies whether the volume is sensitive or not. + Use the string ``dead'' for the non-senstive volume (i.e.\ for the dead material), + and the string ``musr/ScintSD'' for a scintillator (a sensitive volume, i.e.\ + a volume where hits are observed). No other detector type + (other than ``dead'' and ``musr/ScintSD'') is supported at the moment, but + the program might be extended in the future (e.g. to properly include also the + semiconductor tracking detectors, etc.). + \item \emph{idNumber} -- idNumber serves as a unique identifier of the volume. It is primarily + used in the output Root tree to identify the volume: 1) in which muons stop + (tree variable ``muDecayDetID''), + 2) in which hits were deposited in case of sensitive volume + (the variable ``det\_ID[det\_n]''). + \end{itemize} +%tubs beampipeA 0 128 500 0 360 G4_Galactic 0 0 -800 log_World norot dead 232 + +\item{\bf /musr/command logicalVolumeToBeReweighted mu \emph{logicalVolume}=string \emph{weight}=int }\\ + (default: not defined; no reweighting is done unless explicitly requested by this command.) \\ + Events can be reweighted by this command. If muon {\bf stops and decays} in the + volume \emph{logicalVolume}, the event will be reweighted using the requested \emph{weight}. + Namely, only each $n^{th}$ event will be stored ($n=$\emph{weight}) with the parameter + ``weight'' in the Root output tree set to \emph{weight}, while other (non-$n^{th}$) events + will be aborted. (The decision which event is to be stored and which to be aborted is + done at random). This reweighting might be usefull in the cases when the user wants to speed-up the + simulation (respectively to reduce the number of fully simulated events), while keeping + the high number of events interesting for the analysis. For example, one can set + the reweighting of events in which muons stop in the collimator. One should then + use the \emph{weight} stored in the Root tree when filling histograms. + Compared to the simulation with no weighting applied, the histograms with weighted events + will have larger errors, but the distribution should not differ more then within the + statistical errors.\\ + Note that the \emph{weight} parameter is integer, and ``mu'' stands for ``muons'' + (at the moment reweighting based on electrons or positrons is not supported). + + +\end{description} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Visualisation} + +\begin{description} +\item{\bf /musr/command visattributes \emph{volumeName} \emph{color}}\\ + {\bf /musr/command visattributes \emph{materialName} \emph{color}}\\ + In case of visualisation, + one can set the color of a logical volume \emph{volumeName} or of all volumes made + of the material with the name \emph{materialName}. The distinction between the + two options is by the first four letters of the \emph{volumeName} -- if it contains + the string ``log\_'', it is considered as \emph{volumeName}, otherwise it is + considered to be a material with \emph{materialName}. + + Presently the following colors are predefined: ``invisible'', ``white'', ``black'', + ``red'', ``green'', ``blue'', ``lightblue'', ``yellow'', ``gray'', ``cyan'' and ``magenta''. + New colours can be easily added, if needed, in the member function + ``musrDetectorConstruction::SetColourOfLogicalVolume''. + +\end{description} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Physics processes} + +\begin{description} +\item{\bf /musr/command process addDiscreteProcess \emph{particle}=string \emph{process}=string }\\ +{\bf /musr/command process addProcess \emph{particle}=string \emph{process}=string \emph{ordAtRestDoIt}=int \emph{ordAlongSteptDoIt}=int \emph{ordPostStepDoIt}=int }\\ + Adds processes for particles. See {\sc Geant4} manual for more details. Look in the + file musrPhysicsList.cc for the list of defined processes (e.g. G4MultipleScattering, + G4eIonisation, ...) + + There is one special process, combined from G4MultipleScattering and G4CoulombScattering, + defined by the following command:\\ +{\bf /musr/command process addProcess \emph{particle}=string MultipleAndCoulombScattering \emph{ordAtRestDoIt}=int \emph{ordAlongSteptDoIt}=int \emph{ordPostStepDoIt}=int \emph{G4Region1}=string [\emph{G4Region2}=string] [\emph{G4Region3}=string] }\\ + The G4MultipleScattering (rough but very fast approximation of scattering) will be applied + elswhere in the detector, except for the \emph{G4Region1} (and eventually \emph{G4Region2} + and \emph{G4Region3}), where more precise but very slow process G4CoulombScattering + will be applied instead of G4MultipleScattering. Note that up to three + G4Regions are supported at the moment, but this limitation is not intrinsic to {\sc Geant4} + and it can be therefore changed in musrPhysicsList.cc, if needed. The G4Regions have to + be defined in the detector construction phase by the command ``/musr/command region define ...''. + +\end{description} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\clearpage +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Output root tree variables} +The value of -999 or -1000 indicates that the given variable could not be filled +(was undefined in a given event). +For example if the variable ``muTargetTime'' is set to -1000 it means that the initial muon missed the sample, +and therefore no time can be assigned to the sample hit. + +\begin{description} +\item{\bf runID} (Int\_t) -- run ID number. +\item{\bf eventID} (Int\_t) -- event ID number. +\item{\bf weight} (Double\_t) -- event weight. +\item{\bf BFieldAtDecay\_Bx, BFieldAtDecay\_By, BFieldAtDecay\_Bz, BFieldAtDecay\_B3, BFieldAtDecay\_B4, BFieldAtDecay\_B5} (Double\_t) -- + value of the 6 coordinates of the electromagnetic field at the position and time where and when the muon decayed. + The first three coordinates correspond to the magnetic field, the last three to the electric field. +\item{\bf muIniPosX, muIniPosY, muIniPosZ} (Double\_t) -- initial position where muon was generated (in mm). +\item{\bf muIniMomX, muIniMomY, muIniMomZ} (Double\_t) -- initial momentum of the muon when it was generated (in MeV/c). +\item{\bf muIniPolX, muIniPolY, muIniPolZ} (Double\_t) -- initial polarisation of the muon when it was generated. +\item{\bf muDecayDetID} (Int\_t) -- ID number of the detector in which the muon stopped and decayed. +\item{\bf muDecayPosX, muDecayPosY, muDecayPosZ} (Double\_t) -- the position where the muon stopped and decayed (in mm). +\item{\bf muDecayTime} (Double\_t) -- the time at which the muon stopped and decayed (in $\mu$s). +\item{\bf muDecayPolX, muDecayPolY, muDecayPolZ} (Double\_t) -- polarisation of the muon when it stopped and decayed. +\item{\bf muTargetTime} (Double\_t) -- time at which the muon entered the volume whose name starts by ``target'' -- usually the sample (in $\mu$s). +\item{\bf muTargetPolX, muTargetPolY, muTargetPolZ} (Double\_t) -- polarisation of the muon when it entered the volume whose name starts with ``target'' -- usually the sample. +\item{\bf muM0Time} (Double\_t) -- time at which the muon entered the detector called ``M0'' or ``m0'' (in $\mu$s). +\item{\bf muM0PolX, muM0PolY, muM0PolZ} (Double\_t) -- polarisation of the muon when it entered the detector called ``M0'' or ``m0''. +\item{\bf muM1Time} (Double\_t) -- time at which the muon entered the detector called ``M1'' or ``m1'' (in $\mu$s). +\item{\bf muM1PolX, muM1PolY, muM1PolZ} (Double\_t) -- polarisation of the muon when it entered the detector called ``M1'' or ``m1''. +\item{\bf muM2Time} (Double\_t) -- time at which the muon entered the detector called ``M2'' or ``m2'' (in $\mu$s). +\item{\bf muM2PolX, muM2PolY, muM2PolZ} (Double\_t) -- polarisation of the muon when it entered the detector called ``M2'' or ``m2''. +\item{\bf posIniMomX, posIniMomY, posIniMomY} (Double\_t) -- Initial momentum of the decay positron (in MeV/c). +\item{\bf nFieldNomVal} (Int\_t) -- number of the elementary fields that make together the global field. +\item{\bf fieldNomVal[nFieldNomVal]} (array of Double\_t) -- nominal values of all elementary fields. + (They are usually constant, but sometimes they may vary from event to event). +\item{\bf BxIntegral, ByIntegral, BzIntegral, BzIntegral1, BzIntegral2, BzIntegral3} (Double\_t) -- + calculates the field integrals along the muon path and path lengths defined as + \begin{eqnarray} + \mathrm{BxIntegral} & = & \int_{\mu\ \mathrm{path}} B_x(s)\, ds \\ + \mathrm{ByIntegral} & = & \int_{\mu\ \mathrm{path}} B_y(s)\, ds \\ + \mathrm{BzIntegral} & = & \int_{\mu\ \mathrm{path}} B_z(s)\, ds \\ + \mathrm{BzIntegral1} & = & \int_{Z_0}^{Z_{decay}} B_z(z)\, dz \\ + \mathrm{BzIntegral2} & = & \int_{\mu\ \mathrm{path}} ds \\ + \mathrm{BzIntegral3} & = & \int_{Z_0}^{Z_{decay}} dz + \end{eqnarray} + The units are tesla$\cdot$m (for the first four variables) and mm (for the last two variables). + To calculate the integrals properly, the user must force Geant to use very small step size + (e.g.\ by using something like ``/musr/command globalfield setparameter SetLargestAcceptableStep 2''), + and probably also to generate the muons well outside the magnetic field and put target such + that muons stop at $z=0$. + + Note that these variables are by default not calculated (and not stored) and therefore the user has + to switch the calculation on by ``/musr/command rootOutput fieldIntegralBx on'' in the macro file. + +\item{\bf det\_n} (Int\_t) -- number of ``detector hits'' in this event. Note that more then 1 detector + might be hit, and even the same detector might be hit more than once. The hit might be induced by just one + particle, by more then one particle originating from the same particle initially hitting the detector, + or from more ``independent'' particles. + For example, the decay positron can emit an Bremsstrahlung photon in the sample and then both the Bremsstrahlung + photon and positron hit the same positron counter at approximately the same time. +\item{\bf det\_ID[det\_n]} (array of Int\_t) -- ID number of the detector where the given hit occurred. +\item{\bf det\_edep[det\_n]} (array of Double\_t) -- energy deposited in the given hit (in MeV). +\item{\bf det\_edep\_el[det\_n]} (array of Double\_t) -- energy deposited in the given hit due to electron-based interactions (in MeV). +\item{\bf det\_edep\_pos[det\_n]} (array of Double\_t) -- energy deposited in the given hit due to positron-based interactions (in MeV). +\item{\bf det\_edep\_gam[det\_n]} (array of Double\_t) -- energy deposited in the given hit due to photon-based interactions (in MeV). +\item{\bf det\_edep\_mup[det\_n]} (array of Double\_t) -- energy deposited in the given hit due to muon-based interactions (in MeV). +\item{\bf det\_nsteps[det\_n]} (array of Int\_t) -- number of ``steps'' (in {\sc Geant4} terminology) that were + integrated together in the given hit. (The det\_edep[] energy is the sum of the energy deposits during all these steps). +\item{\bf det\_length[det\_n]} (array of Double\_t) -- the length of the trajectory of the particle (particles) that contributed to + the given hit (in mm). +\item{\bf det\_time\_start[det\_n], det\_time\_end[det\_n]} (array of Double\_t) -- the initial and final time belonging of the hit. + It should be the ``global time'' of the track when the first and last hit occurred (in $\mu$s). +\item{\bf det\_x[det\_n], det\_y[det\_n], det\_z[det\_n]} (array of Double\_t) -- the coordinates of the first step of the given hit. +%\item{\bf det\_kine[det\_n]} (array of Double\_t) -- should be kinetic energy, but not sure whether it is filled correctly (in MeV). +\item{\bf det\_Vrtx*****[det\_n]} -- All the variables starting with ``det\_Vrtx'' refer to the particle with the first (in time) energy deposit + belonging to the given hit. (Note that the hit might be induceed by more than one particle.) The vertex, at which + the particle was created, may or may not be positioned within the sensitive volume, in which the hit is observed. +\item{\bf det\_VrtxKine[det\_n]} (array of Double\_t) -- the kinetic energy of the first (in time) particle belonging to the hit. +\item{\bf det\_VrtxX[det\_n], det\_VrtxY[det\_n], det\_VrtxZ[det\_n]} (array of Double\_t) -- the position of the vertex of + the first particle that belongs to the given hit (in mm). +\item{\bf det\_VrtxVolID[det\_n]} (array of Int\_t) -- ID of the detector in which the vertex (see above) was created. +\item{\bf det\_VrtxProcID[det\_n]} (array of Int\_t) -- ID of the physics process in which the vertex (see above) was created. +\item{\bf det\_VrtxTrackID[det\_n]} (array of Int\_t) -- track ID of the first particle that belongs to the given hit. + If the track ID is negative, there were more than just one track contributing to this hit. The absolute value + of det\_VrtxTrackID[det\_n] corresponds to the first (in time) track. +\item{\bf det\_VrtxParticleID[det\_n]} (array of Int\_t) -- particle ID of the first particle that belongs to the given hit. +\item{\bf det\_Vvv*****[det\_n]} -- similar to the variables det\_Vrtx*****[det\_n] above, but if the first particle + belonging to the hit was created inside of the logical volume where the hit occurs, then it's track is followed + to its mother track (even several times) until the track (particle) is found that has been created outside the + given volume. This way one can better investigate which (hopefully) single particle coused the hit. Even though + even in this case it is not guarranteed that only a single particle gave origin to the hit, it is quite likely, though, + that it was in fact just a single particle. If the +\item{\bf save\_n} (Int\_t) -- number of special kind of ``save'' volume that were hit in this event. The ``save volume'' is + any volume whose name starts with letters ``save''. Their purpose in the simulation is usually to check positions + and momenta of particles at some position of the detector, even if the particle does not deposit any energy in + the given ``save'' volume. Save volumes can therefore be made of vacuum. +\item{\bf save\_detID[save\_n]} (array of Int\_t) -- ID number of the save volume. +\item{\bf save\_particleID[save\_n]} (array of Int\_t) -- particle ID of the particle that entered the save volume. +\item{\bf save\_x[save\_n], save\_y[save\_n], save\_z[save\_n]} (array of Double\_t) -- position of the particle where it + entered the save volume (``GetPreStepPoint()'') (in mm). +\item{\bf save\_px[save\_n], save\_py[save\_n], save\_pz[save\_n]} (array of Double\_t) -- momentum of the particle when it + entered the save volume (in GeV). + +\end{description} +\clearpage +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +% +%\begin{figure}\centering +%\epsfig{file=pict/HiFi_01.eps,width=\linewidth,% +%bbllx=56pt,bblly=288pt,bburx=505pt,bbury=555pt,clip=} +%\caption{The cross-section of the first version of the High Field \musr\ apparatus including +%an example interaction. Only the inner part of the apparatus is shown. The picture was generated +%using GEANT package.} +%\label{HiFi_01} +%\end{figure} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Conclusions} +The ... +in~\cite{Aktas:2004px}. + +\section{Appendix A: Steering file for the simulation} +\begin{verbatim} +# Macro file for seg06.cc +# set detector parameters +# This line fills some space +# This line fills some space +/run/beamOn 2 +\end{verbatim} + + +\begin{thebibliography}{0} + +%\cite{Aktas:2004px} +\bibitem{Aktas:2004px} +A.~Aktas {\it et al.} [H1 Collaboration], +%``Measurement of dijet production at low Q**2 at HERA,'' +Submitted to Eur.\,Phys.\,J.\,{\bf C}, [hep-ex/0401010]. +%%CITATION = HEP-EX 0401010;%% + + + + +\end{thebibliography} + +\end{document} diff --git a/include/BLEngeFunction.hh b/include/BLEngeFunction.hh new file mode 100644 index 0000000..62d0f0f --- /dev/null +++ b/include/BLEngeFunction.hh @@ -0,0 +1,160 @@ +// BLEngeFunction.hh +/* +This source file is part of G4beamline, http://g4beamline.muonsinc.com +Copyright (C) 2003,2004,2005,2006 by Tom Roberts, all rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +http://www.gnu.org/copyleft/gpl.html +*/ + +#ifndef BLENGEFUNCTION_HH +#define BLENGEFUNCTION_HH + +#include + +/** enum BLEngeType specifies the default parameters of BLEngeFunction. + **/ +enum BLEngeType { ENGE_BLOCK, ENGE_BEND, ENGE_QUAD, ENGE_OTHER }; + +/** class EngeFunction implements the Enge function for fringe fields. + * + * z is the distance from the nominal edge, with z=0 being the edge. + * it should be divided by the aperture diameter or full width/height. + * z<0 is inside, z>0 is outside. + * + * See the COSY reference manual (pp 32-35) for suggested values of + * a1-a6, or use the ENGE_BEND or ENGE_QUAD types (which come from there). + * http://cosy.pa.msu.edu/cosymanu/index.html + * + * Mathematica was used to compute the derivatives. + **/ +class BLEngeFunction { + BLEngeType type; + double a1,a2,a3,a4,a5,a6; +public: + /// default constructor. + BLEngeFunction() { type=ENGE_BLOCK; set(0,0,0,0,0,0); } + /// constructor for common magnet types. + BLEngeFunction(BLEngeType t) { + switch(t) { + case ENGE_BLOCK: + case ENGE_OTHER: + set(0,0,0,0,0,0); + break; + case ENGE_BEND: + set(0.478959,1.911289,-1.185953,1.630554,-1.082657,0.318111); + break; + case ENGE_QUAD: + set(0.296471,4.533219,-2.270982,1.068627,-0.036391,0.022261); + break; + } + type = t; + } + /// general constructor. + BLEngeFunction(double _a1, double _a2, double _a3, double _a4, + double _a5, double _a6) { + set(_a1,_a2,_a3,_a4,_a5,_a6); + } + /// set the parameters. + void set(double _a1, double _a2, double _a3, double _a4, + double _a5, double _a6) { + a1=_a1; a2=_a2; a3=_a3; a4=_a4; a5=_a5; a6=_a6; + if(a1==0.0 && a2==0.0 && a3==0.0 && a4==0.0 && a5==0.0 && + a6==0.0) + type = ENGE_BLOCK; + else + type = ENGE_OTHER; + } + /// evaluate the Enge function at z. + double operator()(double z) const { + if(type == ENGE_BLOCK) return (z<=0.0 ? 1.0 : 0.0); + if(z < -4.0) return 1.0; + if(z > 4.0) return 0.0; + return 1.0/(1.0+exp(a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6)))))); + } + /// evaluate the derivative of the Enge function at z. + double prime(double z) const { + if(type == ENGE_BLOCK) return 0.0; + if(fabs(z) > 4.0) return 0.0; + double exp1 = exp(a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6))))); + return -exp1/(1.0+exp1)/(1.0+exp1)* + (a2+z*(2.0*a3+z*(3.0*a4+z*(4.0*a5+z*5.0*a6)))); + } + double first(double z) { return prime(z); } + /// evaluate the second derivative of the Enge function at z. + double second(double z) const { + if(type == ENGE_BLOCK) return 0.0; + if(fabs(z) > 4.0) return 0.0; + double f1 = a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6)))); + double f2 = (a2+2*a3*z+3*a4*z*z+4*a5*z*z*z+5*a6*z*z*z*z); + double f3 = (2*a3+6*a4*z+12*a5*z*z+20*a6*z*z*z); + double exp1 = exp(f1); + return exp1*((exp1-1.0)*f2*f2-(1.0+exp1)*f3)/ + (1.0+exp1)/(1.0+exp1)/(1.0+exp1); + } + /// evaluate the third derivative of the Enge function at z. + double third(double z) const { + if(type == ENGE_BLOCK) return 0.0; + if(fabs(z) > 4.0) return 0.0; + double f1 = a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6)))); + double f2 = a2+z*(2*a3+z*(3*a4+4*a5*z+5*a6*z*z)); + double f3 = 2*(a3+z*(3*a4+2*z*(3*a5+5*a6*z))); + double f4 = a4+2.0*z*(2.0*a5+5.0*a6*z); + double exp1 = exp(f1); + double onepexp1 = 1.0 + exp1; + return -exp1*(6*exp1*exp1*f2*f2*f2-6*exp1*f2*(f2*f2+f3)*onepexp1 + +(f2*f2*f2+3*f2*f3+6*f4)*onepexp1*onepexp1) + /(onepexp1*onepexp1*onepexp1*onepexp1); + } + /// evaluate the fourth derivative of the Enge function at z. + double fourth(double z) const { + if(type == ENGE_BLOCK) return 0.0; + if(fabs(z) > 4.0) return 0.0; + double f1 = a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6)))); + double f2 = a2+z*(2*a3+z*(3*a4+4*a5*z+5*a6*z*z)); + double f3 = 2*(a3+z*(3*a4+2*z*(3*a5+5*a6*z))); + double f4 = a4+2.0*z*(2.0*a5+5.0*a6*z); + double f5 = a5 + 5*a6*z; + double exp1 = exp(f1); + double onepexp1 = 1.0 + exp1; + return -exp1*(-24*exp1*exp1*exp1*f2*f2*f2*f2+onepexp1* + (36*exp1*exp1*f2*f2*(f2*f2+f3)-2*exp1*(7*f2*f2*f2*f2 + +18*f2*f2*f3+3*f3*f3+24*f2*f4)*onepexp1 + +(f2*f2*f2*f2+6*f2*f2*f3+3*f3*f3+24*f2*f4+24*f5) + *onepexp1*onepexp1)) + /(onepexp1*onepexp1*onepexp1*onepexp1*onepexp1); + } + /// evaluate the fifth derivative of the Enge function at z. + double fifth(double z) const { + if(type == ENGE_BLOCK) return 0.0; + if(fabs(z) > 4.0) return 0.0; + double f1 = a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6)))); + double f2 = a2+z*(2*a3+z*(3*a4+4*a5*z+5*a6*z*z)); + double f3 = 2*(a3+z*(3*a4+2*z*(3*a5+5*a6*z))); + double f4 = a4+2.0*z*(2.0*a5+5.0*a6*z); + double f5 = a5 + 5*a6*z; + double exp1 = exp(f1); + double onepexp1 = 1.0 + exp1; + return -exp1/(onepexp1*onepexp1*onepexp1*onepexp1*onepexp1*onepexp1) + *(120*exp1*exp1*exp1*exp1*f2*f2*f2*f2*f2 + -240*exp1*exp1*exp1*f2*f2*f2*(f2*f2+f3)*onepexp1 + +onepexp1*onepexp1*(30*exp1*exp1*f2*(5*f2*f2*f2*f2 + +12*f2*f2*f3+3*f3*f3+12*f2*f4)-10*exp1*(3*f2*f2*f2*f2*f2 + +14*f2*f2*f2*f3+9*f2*f3*f3+36*f2*f2*f4+12*f3*f4+24*f2*f5) + *onepexp1+(120*a6+f2*f2*f2*f2*f2+10*f2*f2*f2*f3+60*f2*f2*f4 + +60*f3*f4+15*f2*(f3*f3+8*f5))*onepexp1*onepexp1)); + } + /// return the type of Enge function + BLEngeType getType() const { return type; } +}; + +#endif // BLENGEFUNCTION_HH diff --git a/include/F04ElementField.hh b/include/F04ElementField.hh new file mode 100644 index 0000000..c08d5d4 --- /dev/null +++ b/include/F04ElementField.hh @@ -0,0 +1,171 @@ +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// +// + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... + +#ifndef F04ElementField_h +#define F04ElementField_h 1 + +#include "globals.hh" + +#include "G4Navigator.hh" +#include "G4TransportationManager.hh" + +#include "G4UserLimits.hh" +#include "G4VisAttributes.hh" + +// class F04ElementField - interface for the EM field of one element + +// This is the interface class used by GlobalField to compute the field +// value at a given point[]. + +// An element that represents an element with an EM field will +// derive a class from this one and implement the computation for the +// element. The construct() function will add the derived object into +// GlobalField. + +class F04ElementField +{ + + private: + + F04ElementField& operator=(const F04ElementField&); + + public: + + /// Constructor. + F04ElementField(const G4ThreeVector, G4LogicalVolume*); + + /// the actual implementation constructs the F04ElementField + void construct(); + + /// Destructor. + virtual ~F04ElementField() { if (aNavigator) delete aNavigator; } + + /// setMaxStep(G4double) sets the max. step size + void setMaxStep(G4double s) + { + maxStep = s; + userLimits->SetMaxAllowedStep(maxStep); + lvolume->SetUserLimits(userLimits); + } + + /// getMaxStep() returns the max. step size + G4double getMaxStep() { return maxStep; } + + /// setColor(G4String) sets the color + void setColor(G4String c) + { + color = c; + lvolume->SetVisAttributes(getVisAttribute(color)); + } + + /// getColor() returns the color + G4String getColor() { return color; } + + /// getVisAttribute() returns the appropriate G4VisAttributes. + static G4VisAttributes* getVisAttribute(G4String color); + + /// setGlobalPoint() ensures that the point is within the global + /// bounding box of this ElementField's global coordinates. + /// Normally called 8 times for the corners of the local bounding + /// box, after a local->global coordinate transform. + /// If never called, the global bounding box is infinite. + /// BEWARE: if called only once, the bounding box is just a point. + void setGlobalPoint(const G4double point[4]) + { + if(minX == -DBL_MAX || minX > point[0]) minX = point[0]; + if(minY == -DBL_MAX || minY > point[1]) minY = point[1]; + if(minZ == -DBL_MAX || minZ > point[2]) minZ = point[2]; + if(maxX == DBL_MAX || maxX < point[0]) maxX = point[0]; + if(maxY == DBL_MAX || maxY < point[1]) maxY = point[1]; + if(maxZ == DBL_MAX || maxZ < point[2]) maxZ = point[2]; + } + + /// isInBoundingBox() returns true if the point is within the + /// global bounding box - global coordinates. + bool isInBoundingBox(const G4double point[4]) const + { + if(point[2] < minZ || point[2] > maxZ) return false; + if(point[0] < minX || point[0] > maxX) return false; + if(point[1] < minY || point[1] > maxY) return false; + return true; + } + + /// addFieldValue() will add the field value for this element to field[]. + /// Implementations must be sure to verify that point[] is within + /// the field region, and do nothing if not. + /// point[] is in global coordinates and geant4 units; x,y,z,t. + /// field[] is in geant4 units; Bx,By,Bz,Ex,Ey,Ez. + /// For efficiency, the caller may (but need not) call + /// isInBoundingBox(point), and only call this function if that + /// returns true. + virtual void + addFieldValue(const G4double point[4], G4double field[6]) const = 0; + + virtual G4double getLength() = 0; + virtual G4double getWidth() = 0; + virtual G4double getHeight() = 0; + + void SetElementFieldName(G4String name) {elementFieldName=name;} + G4String GetElementFieldName() {return elementFieldName;} + void SetEventNrDependentField(G4double initialField, G4double finalField, G4int nrOfSteps); + std::map GetEventNrDependentField() const {return changeFieldInStepsMap;} + void SetElementFieldValueIfNeeded(G4int eventNr); + + virtual G4double GetNominalFieldValue() = 0; + virtual void SetNominalFieldValue(G4double newFieldValue) =0; + + + protected: + + G4LogicalVolume* lvolume; + + G4AffineTransform global2local; + +// F04ElementField(const F04ElementField&); + + private: + + static G4Navigator* aNavigator; + + G4String color; + + G4ThreeVector center; + G4double minX, minY, minZ, maxX, maxY,maxZ; + + G4double maxStep; + G4UserLimits* userLimits; + + G4String elementFieldName; + std::map changeFieldInStepsMap; +}; + +#endif diff --git a/include/F04FieldMessenger.hh b/include/F04FieldMessenger.hh new file mode 100644 index 0000000..7e09d06 --- /dev/null +++ b/include/F04FieldMessenger.hh @@ -0,0 +1,73 @@ +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// +// + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... + +#ifndef F04FieldMessenger_h +#define F04FieldMessenger_h 1 + +#include "globals.hh" +#include "G4UImessenger.hh" + +class F04GlobalField; +class G4UIdirectory; +class G4UIcmdWithAString; +class G4UIcmdWithAnInteger; +class G4UIcmdWithADoubleAndUnit; +class G4UIcmdWithoutParameter; + +class F04FieldMessenger: public G4UImessenger +{ + public: + F04FieldMessenger(F04GlobalField* ); + ~F04FieldMessenger(); + + void SetNewValue(G4UIcommand*, G4String); + void SetNewValue(G4UIcommand*, G4int); + + private: + + F04GlobalField* fGlobalField; + + G4UIdirectory* detDir; + + G4UIcmdWithAnInteger* fStepperCMD; + G4UIcmdWithADoubleAndUnit* fMinStepCMD; + G4UIcmdWithADoubleAndUnit* fDeltaChordCMD; + G4UIcmdWithADoubleAndUnit* fDeltaOneStepCMD; + G4UIcmdWithADoubleAndUnit* fDeltaIntersectionCMD; + G4UIcmdWithADoubleAndUnit* fEpsMinCMD; + G4UIcmdWithADoubleAndUnit* fEpsMaxCMD; + G4UIcmdWithoutParameter* fUpdateCMD; + +}; + +#endif + diff --git a/include/F04GlobalField.hh b/include/F04GlobalField.hh new file mode 100644 index 0000000..65501e3 --- /dev/null +++ b/include/F04GlobalField.hh @@ -0,0 +1,195 @@ +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// +// + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... + +#ifndef F04GlobalField_h +#define F04GlobalField_h 1 + +#include + +#include "G4FieldManager.hh" +#include "G4PropagatorInField.hh" +#include "G4MagIntegratorStepper.hh" +#include "G4ChordFinder.hh" + +//#include "G4MagneticField.hh" +#include "G4ElectroMagneticField.hh" + +#include "G4Mag_EqRhs.hh" +#include "G4Mag_SpinEqRhs.hh" + +#include "G4EqMagElectricField.hh" +#include "G4EqEMFieldWithSpin.hh" + +#include "F04FieldMessenger.hh" +#include "F04ElementField.hh" + +// F04GlobalField - handles the global ElectroMagnetic field +// +// There is a single G04GlobalField object. +// +// The field from each individual beamline element is given by a +// ElementField object. Any number of overlapping ElementField +// objects can be added to the global field. Any element that +// represents an element with an EM field must add the appropriate +// ElementField to the global GlobalField object. + +typedef std::vector FieldList; + +class F04GlobalField : public G4ElectroMagneticField { +//class F04GlobalField : public G4MagneticField { + +private: + + F04GlobalField(); + F04GlobalField(const F04GlobalField&); + +public: + ~F04GlobalField(); + +private: + F04GlobalField& operator=(const F04GlobalField&); + + void setupArray(); + +public: + + /// getObject() returns the single F04GlobalField object. + /// It is constructed, if necessary. + static F04GlobalField* getObject(); + + // + static G4bool Exists() {if (object==NULL) {return false;} else {return true;}; } + + /// GetFieldValue() returns the field value at a given point[]. + /// field is really field[6]: Bx,By,Bz,Ex,Ey,Ez. + /// point[] is in global coordinates: x,y,z,t. + void GetFieldValue(const G4double* point, G4double* field) const; + + /// DoesFieldChangeEnergy() returns true. + // cks - for testing just on magnetic field use DoesFieldChangeEnergy()=false; + G4bool DoesFieldChangeEnergy() const { return true; } + // G4bool DoesFieldChangeEnergy() const { return false; } + + /// addElementField() adds the ElementField object for a single + /// element to the global field. + void addElementField(F04ElementField* f) { if (fields) fields->push_back(f); } + + /// clear() removes all ElementField-s from the global object, + /// and destroys them. Used before the geometry is completely + /// re-created. + void clear(); + + /// updates all field tracking objects and clear() + void updateField(); + + /// Set the Stepper types + void SetStepperType( G4int i ) { fStepperType = i; } + + /// Set the Stepper + void SetStepper(); + + /// Set the minimum step length + void SetMinStep(G4double s) { minStep = s; G4cout<<"F04GlobalField::SetMinStep: minStep set to "< pointsAtWhichUserWantsToPrintFieldValue; + +private: + + G4int fStepperType; + + G4double minStep; + G4double deltaChord; + G4double deltaOneStep; + G4double deltaIntersection; + G4double epsMin; + G4double epsMax; + +// G4Mag_EqRhs* fEquation; +// G4Mag_SpinEqRhs* fEquation; +// G4EqMagElectricField* fEquation; + G4EqEMFieldWithSpin* fEquation; + + G4FieldManager* fFieldManager; + G4PropagatorInField* fFieldPropagator; + G4MagIntegratorStepper* fStepper; + G4ChordFinder* fChordFinder; + + F04FieldMessenger* fFieldMessenger; + + std::map globalChangeFieldInStepsMap; + +}; + +#endif diff --git a/include/MuDecayChannel.hh b/include/MuDecayChannel.hh new file mode 100644 index 0000000..76609f2 --- /dev/null +++ b/include/MuDecayChannel.hh @@ -0,0 +1,71 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// $Id: G4MuonDecayChannel.hh,v 1.6 2006/06/29 19:23:35 gunter Exp $ +// GEANT4 tag $Name: geant4-09-00 $ +// +// +// ------------------------------------------------------------ +// GEANT 4 class header file +// +// History: first implementation, based on object model of +// 30 May 1997 H.Kurashige +// ------------------------------------------------------------ +#ifndef MuDecayChannel_h +#define MuDecayChannel_h 1 + +#include "G4ios.hh" +#include "globals.hh" +#include "G4VDecayChannel.hh" + +class MuDecayChannel :public G4VDecayChannel +{ + // Class Decription + // This class describes muon decay kinemtics. + // This version neglects muon polarization + // assumes the pure V-A coupling + // gives incorrect energy spectrum for neutrinos + // + + public: // With Description + //Constructors + MuDecayChannel(const G4String& theParentName, + G4double theBR); + // Destructor + virtual ~MuDecayChannel(); + + public: // With Description + virtual G4DecayProducts *DecayIt(G4double); + +}; + + +#endif diff --git a/include/MuDecayChannelWithSpin.hh b/include/MuDecayChannelWithSpin.hh new file mode 100644 index 0000000..11474af --- /dev/null +++ b/include/MuDecayChannelWithSpin.hh @@ -0,0 +1,130 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// ------------------------------------------------------------ +// GEANT 4 class header file +// +// History: +// 17 August 2004 P.Gumplinger and T.MacPhail +// samples Michel spectrum including 1st order +// radiative corrections +// Reference: Florian Scheck "Muon Physics", in Physics Reports +// (Review Section of Physics Letters) 44, No. 4 (1978) +// 187-248. North-Holland Publishing Company, Amsterdam +// at page 210 cc. +// +// W.E. Fisher and F. Scheck, Nucl. Phys. B83 (1974) 25. +// +// ------------------------------------------------------------ +#ifndef MuDecayChannelWithSpin_hh +#define MuDecayChannelWithSpin_hh 1 + +#include "globals.hh" +#include "G4ThreeVector.hh" +#include "MuDecayChannel.hh" + +class MuDecayChannelWithSpin : public MuDecayChannel +{ + // Class Decription + // This class describes muon decay kinemtics. + // This version assumes V-A coupling with 1st order radiative correctons, + // the standard model Michel parameter values, but + // gives incorrect energy spectrum for neutrinos + +public: // With Description + + //Constructors + MuDecayChannelWithSpin(const G4String& theParentName, + G4double theBR); + // Destructor + virtual ~MuDecayChannelWithSpin(); + +public: // With Description + + virtual G4DecayProducts *DecayIt(G4double); + + void SetPolarization(G4ThreeVector); + const G4ThreeVector& GetPolarization() const; + +private: + + G4ThreeVector parent_polarization; + +// Radiative Correction Factors + + G4double F_c(G4double x, G4double x0); + G4double F_theta(G4double x, G4double x0); + G4double R_c(G4double x); + + G4double EMMU; + G4double EMASS; + +}; + +inline void MuDecayChannelWithSpin::SetPolarization(G4ThreeVector polar) +{ + parent_polarization = polar; +} + +inline const G4ThreeVector& MuDecayChannelWithSpin::GetPolarization() const +{ + return parent_polarization; +} + +inline G4double MuDecayChannelWithSpin::F_c(G4double x, G4double x0) +{ + G4double omega = std::log(EMMU/EMASS); + + G4double f_c; + + f_c = (5.+17.*x-34.*x*x)*(omega+std::log(x))-22.*x+34.*x*x; + f_c = (1.-x)/(3.*x*x)*f_c; + f_c = (6.-4.*x)*R_c(x)+(6.-6.*x)*std::log(x) + f_c; + f_c = (fine_structure_const/twopi) * (x*x-x0*x0) * f_c; + + return f_c; +} + +inline G4double MuDecayChannelWithSpin::F_theta(G4double x, G4double x0) +{ + G4double omega = std::log(EMMU/EMASS); + + G4double f_theta; + + f_theta = (1.+x+34*x*x)*(omega+std::log(x))+3.-7.*x-32.*x*x; + f_theta = f_theta + ((4.*(1.-x)*(1.-x))/x)*std::log(1.-x); + f_theta = (1.-x)/(3.*x*x) * f_theta; + f_theta = (2.-4.*x)*R_c(x)+(2.-6.*x)*std::log(x)-f_theta; + f_theta = (fine_structure_const/twopi) * (x*x-x0*x0) * f_theta; + + return f_theta; +} + +#endif diff --git a/include/meyer.hh b/include/meyer.hh new file mode 100644 index 0000000..ce79a8e --- /dev/null +++ b/include/meyer.hh @@ -0,0 +1,70 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$//* +// LOW ENERGY MUON SPIN RELAXATION, ROTATION, RADIATION Geant4 SIMULATION +// ID : MEYER.hh , v 1.0 +// AUTHOR: Taofiq PARAISO +// DATE : 2005-04 +// +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$// +// +// & &&&&&&&&&& &&&&&&& &&&&&&&& +// & & && && & && +// & & & & & & && +// & &&&&&&& & & &&&&&& &&&&&&&& +// & & & && & & && +// & & && & & && && & & +// &&&&&&&&&& &&&&&&&&&& & &&&&& && &&&&&&& & && +// & +// & +// & +// & +// MEYER +/* + fIRST IMPLEMENTATION BY ANLSEM,H. IN FORTRAN + C++ CONVERSION T.K.PARAISO 04-2005 + + !!! IMPORTANT !!! + + Notice: + Tables definition changes between FORTRAN and C++: + 1/ Fortran indices start at 1 and C++ indices start at 0 + 2/ Tables are defined as table[column][row] in Fortran + table[row][column] in c++ + + usefull reference + http://gershwin.ens.fr/vdaniel/Doc-Locale/Langages-Program-Scientific/Fortran/Tutorial/arrays.htm + +*/ +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$// + + +#ifndef meyer_h +#define meyer_h 1 + +#include +#include +#include +#include +#include +#include +#include +#include "globals.hh" + +class meyer +{ + public: + meyer(); + ~meyer(); + + void GFunctions(double*, double*, double); + void Get_F_Function_Meyer(double tau, double Ekin, double Z1, double Z2, double m1, double m2); + void F_Functions_Meyer( double tau,double thetaSchlange,double *f1,double *f2); + void Get_F_Function(double tau,double theta, double Ekin, double Z1, double Z2, double m1, double m2, double* F); + +}; + +#endif diff --git a/include/musrDetectorConstruction.hh b/include/musrDetectorConstruction.hh new file mode 100644 index 0000000..0d326c0 --- /dev/null +++ b/include/musrDetectorConstruction.hh @@ -0,0 +1,60 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#ifndef musrDetectorConstruction_h +#define musrDetectorConstruction_h 1 + +#include "globals.hh" +#include "G4VUserDetectorConstruction.hh" +#include "G4ThreeVector.hh" +#include "G4RotationMatrix.hh" +#include "G4FieldManager.hh" +#include + +class G4Tubs; +class G4Box; +class G4Cons; +class G4Trd; +class G4LogicalVolume; +class G4VPhysicalVolume; +class G4Material; +class musrDetectorMessenger; +class musrScintSD; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class musrDetectorConstruction : public G4VUserDetectorConstruction +{ +public: + + musrDetectorConstruction(); + ~musrDetectorConstruction(); + +public: + + G4VPhysicalVolume* Construct(); + + + void UpdateGeometry(); + void SetInputParameterFileName(G4String fileName) {parameterFileName=fileName;}; + void ReportGeometryProblem(char myString[501]); + void ReportProblemInStearingFile(char* myString); + G4Material* CharToMaterial(char myString[100]); + G4LogicalVolume* FindLogicalVolume(G4String LogicalVolumeName); + void SetColourOfLogicalVolume(G4LogicalVolume* pLogVol,char* colour); + +private: + G4String parameterFileName; // name of the file with the geometry parameters + G4bool checkOverlap; // parameter to check ovelaping volumes + G4double largestAcceptableStep; // parameter defining largest step in the magnetic field + + musrScintSD* aScintSD; + musrDetectorMessenger* detectorMessenger; // pointer to the Messenger + + std::map pointerToRotationMatrix; + std::map pointerToField; + +private: + void DefineMaterials(); +}; + +#endif diff --git a/include/musrDetectorMessenger.hh b/include/musrDetectorMessenger.hh new file mode 100644 index 0000000..05de543 --- /dev/null +++ b/include/musrDetectorMessenger.hh @@ -0,0 +1,49 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#ifndef musrDetectorMessenger_h +#define musrDetectorMessenger_h 1 + +#include "globals.hh" +#include "G4UImessenger.hh" + +class musrDetectorConstruction; +class G4UIdirectory; +class G4UIcmdWithAString; +class G4UIcmdWithADoubleAndUnit; +class G4UIcmdWithAnInteger; +class G4UIcmdWithoutParameter; +class G4UIcmdWith3Vector; +class G4UIcmdWith3VectorAndUnit; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class musrDetectorMessenger: public G4UImessenger +{ + public: + musrDetectorMessenger(musrDetectorConstruction*); + ~musrDetectorMessenger(); + + void SetNewValue(G4UIcommand*, G4String); + + private: + musrDetectorConstruction* myDetector; + + G4UIdirectory* musrDir; + G4UIdirectory* detDir; + G4UIdirectory* runDir; + G4UIcmdWithAString* Ignore1Cmd; + G4UIcmdWithAString* Ignore2Cmd; + G4UIcmdWithAnInteger* RunIDSetCmd; + G4UIcmdWithAnInteger* RandomOptionCmd; + G4UIcmdWithAnInteger* HowOftenToPrintEventCmd; + G4UIcmdWithAnInteger* RndmEventToSaveSeedsCmd; + G4UIcmdWithoutParameter* UpdateCmd; + + public: + +}; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#endif + diff --git a/include/musrErrorMessage.hh b/include/musrErrorMessage.hh new file mode 100644 index 0000000..8ddb629 --- /dev/null +++ b/include/musrErrorMessage.hh @@ -0,0 +1,29 @@ +#ifndef musrErrorMessage_h +#define musrErrorMessage_h 1 + +#include +#include "globals.hh" +enum SEVERITY {INFO, WARNING, SERIOUS, FATAL}; + +typedef struct +{ + SEVERITY mesSeverity; + int nTimes; +} ErrorStruct; + +class musrErrorMessage { + public: + musrErrorMessage(); + ~musrErrorMessage(); + static musrErrorMessage* GetInstance(); + void musrError(SEVERITY severity, G4String message, G4bool silent); + void PrintErrorSummary(); + + private: + static musrErrorMessage* pointerToErrors; + G4int nErrors; + // std::map ErrorMapping; + std::map ErrorMapping; + std::map severityWord; +}; +#endif diff --git a/include/musrEventAction.hh b/include/musrEventAction.hh new file mode 100644 index 0000000..cb1603e --- /dev/null +++ b/include/musrEventAction.hh @@ -0,0 +1,43 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#ifndef musrEventAction_h +#define musrEventAction_h 1 + +#include "globals.hh" +#include "G4UserEventAction.hh" +class G4Timer; +class G4Event; +class musrMagneticField; +class musrTabulatedField3D; +class musrTabulatedField2D; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class musrEventAction : public G4UserEventAction +{ + public: + musrEventAction(); + ~musrEventAction(); + + public: + void BeginOfEventAction(const G4Event*); + void EndOfEventAction(const G4Event*); + static musrEventAction* GetInstance(); + + private: + // pointer to this class + static musrEventAction* pointer; + // + G4Timer* timer; + // Variables for the time-dependent magnetic field + G4bool timeDependentField; + time_t timeOfRunStart; + + public: + static G4int nHowOftenToPrintEvent; + static G4double maximumRunTimeAllowed; +}; + +#endif + + diff --git a/include/musrMuFormation.hh b/include/musrMuFormation.hh new file mode 100644 index 0000000..552716d --- /dev/null +++ b/include/musrMuFormation.hh @@ -0,0 +1,80 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +// Muonium Formation according to yield.cc function (through GetYields method). +// Id : musrMuFormation.hh, v 1.4 +// Author: Taofiq PARAISO, T. Shiroka +// Date : 2007-12 +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + +#ifndef musrMuFormation_h +#define musrMuFormation_h 1 + +#include "G4VDiscreteProcess.hh" +#include "G4ParticleTable.hh" + +#include "yields.hh" + +/*! musrMuFormation class defines the muonium formation process in the Carbon foil + * according to yields from Gonin's paper Sci. Rev. Instrum. 65(3), 648-652 (1994). + * \image html yields3.gif The muonium formation yields. + * The main parameters are the foil thickness and muon energy. For a given energy, + * a corresponding proportion of the muons will be converted into Muonium. + * Concretely, the muon is eliminated and replaced by a Muonium with identical + * properties, including time, energy, momentum, position etc. + * + * The process is executed at the END of a step, i.e. the muon is converted into + * Muonium AFTER flying through the Carbon foil (see also yields.hh). */ + +class musrMuFormation : public G4VDiscreteProcess +{ + public: + + musrMuFormation(const G4String& name = "MuFormation", // process description + G4ProcessType aType = fElectromagnetic); + + ~musrMuFormation(); + + //! - Main method. Muonium formation process is executed at the END of a step. */ + G4VParticleChange* PostStepDoIt( + const G4Track&, + const G4Step&); + + G4double GetMeanFreePath(const G4Track& aTrack, + G4double previousStepSize, + G4ForceCondition* condition); + + + //! Condition for process application (step Object). + G4bool CheckCondition(const G4Step& aStep); + + //! Condition for process application (step Pointer). + G4bool CheckCondition(const G4Step* aStep); + + + G4String p_name; + G4bool condition; + + + void GetDatas( const G4Step* aStep); + // model parameters + G4ParticleTable* particleTable; + G4ParticleDefinition* particle; + Yields Gonin; + G4double yvector[3]; + G4double rnd; + G4DynamicParticle *DP; + + //! The particle change object. + G4VParticleChange fParticleChange; + + void PrepareSecondary(const G4Track&); + G4Track* aSecondary; + + void InitializeSecondaries(const G4Track&); +}; + +#endif diff --git a/include/musrMuScatter.hh b/include/musrMuScatter.hh new file mode 100644 index 0000000..c2a1c57 --- /dev/null +++ b/include/musrMuScatter.hh @@ -0,0 +1,57 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +// Muonium "Scattering" +// Id : musrMuScatter.hh, v 1.4 +// Author: Taofiq PARAISO, T. Shiroka +// Date : 2007-12 +// Notes : Simplified model for Mu scattering. Spin effects have been excluded. +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + +/*! + * musrMuScatter class defines the Muonium scattering process. It implements a very + * basic model which assumes Muonium looses its electron as soon as it enters any + * material (except for vacuum and CFoil). The class has only a PostStepDoIt method. + * The in-flight Muonium spin precession has been supressed. */ + +#ifndef musrMuScatter_h +#define musrMuScatter_h 1 + +#include "G4VDiscreteProcess.hh" + +class musrMuScatter : public G4VDiscreteProcess +{ + public: + musrMuScatter(const G4String& name="MuScatt", // process description + G4ProcessType aType = fGeneral); + + ~musrMuScatter(); + + //! \mm The actions are taken at the end of the step. + G4VParticleChange* PostStepDoIt(const G4Track&, + const G4Step&); + + G4double GetMeanFreePath(const G4Track& aTrack, + G4double previousStepSize, + G4ForceCondition* condition); + + //! The condition for applying the process. + G4bool CheckCondition(const G4Step& aStep); + + + G4bool condition; + G4double itime, gtime, ftime,deltatime; + G4String p_name; + G4DynamicParticle *DP; + G4ParticleChange fParticleChange; + + void PrepareSecondary(const G4Track&); + G4Track* aSecondary; + + void InitializeSecondaries(const G4Track&); +}; + +#endif diff --git a/include/musrMuonium.hh b/include/musrMuonium.hh new file mode 100644 index 0000000..7abafc6 --- /dev/null +++ b/include/musrMuonium.hh @@ -0,0 +1,77 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// $Id: musrMuonium.hh,v 1.10 2006/06/29 19:20:21 gunter Exp $ +// GEANT4 tag $Name: geant4-09-00 $ +// +// +// ------------------------------------------------------------ +// GEANT 4 class header file +// +// History: first implementation, based on object model of +// 4-th April 1996, G.Cosmo +// **************************************************************** +// New implementation as a utility class M.Asai, 26 July 2004 +// ---------------------------------------------------------------- + +#ifndef musrMuonium_h +#define musrMuonium_h 1 + +#include "globals.hh" +#include "G4ios.hh" +#include "G4ParticleDefinition.hh" + +// ###################################################################### +// ### MUONIUM ### +// ###################################################################### + +class musrMuonium : public G4ParticleDefinition +{ + private: + static musrMuonium* theInstance; + musrMuonium(){} + ~musrMuonium(){} + + public: + static musrMuonium* Definition(); + static musrMuonium* MuoniumDefinition(); + static musrMuonium* Muonium(); +}; + +#endif + + + + + + + + diff --git a/include/musrParameters.hh b/include/musrParameters.hh new file mode 100644 index 0000000..70132b3 --- /dev/null +++ b/include/musrParameters.hh @@ -0,0 +1,44 @@ +#ifndef musrParameters_h +#define musrParameters_h 1 + +#include "globals.hh" + +class musrParameters { + public: + musrParameters(G4String steeringFileName); + ~musrParameters(); + + static musrParameters* GetInstance(); + + static G4String mySteeringFileName; // name of the steering file (e.g. the *.mac file) + static G4bool storeOnlyEventsWithHits; // variable specifying whether to store interesting + // or all events into the ROOT tree. (default = true) + static G4int storeOnlyEventsWithHitInDetID; // simillar to "storeOnlyEventsWithHits". The event is stored + // only and only if there was a hit in the detector with the ID + // equal to storeOnlyEventsWithHitInDetID. + // The storeOnlyEventsWithHitInDetID has to be non zero. + static G4double signalSeparationTime; // minimim time separation between two subsequent signal + static G4bool storeOnlyTheFirstTimeHit; // if true, only the hit that happened first will be + // stored, anything else will be ignored + // (usefull for some special studies, not for a serious simulation) + static G4bool killAllPositrons; // if true, all positron tracks will be deleted (usefull for the studies of the muon beam) + static G4bool killAllGammas; // + static G4bool killAllNeutrinos; // + //cks static G4bool includeMuoniumProcesses; // If true, includes Muonium formation and all + //cks // other Mu-related processes in the simulation + static G4bool boolG4GeneralParticleSource; // if true, G4GeneralParticleSource will be initialised instead of G4ParticleGun + // - needed for the radioactive source + static G4bool boolG4OpticalPhotons; // if true, optical photons will be used (in the sensitive scintillators) + static G4bool field_DecayWithSpin; // if true, then the routins for calculating the magnetic field will + // use more precise argument. This variable is set to "true" by + // the SteppinAction and reset to "false" in the GetFieldValue. + // It is being changed on step by step basis. + static G4int nrOfEventsToBeGenerated; // Nr of events to be simulated in this run (set by /run/beamOn command) + private: + static musrParameters* pointerToParameters; + G4bool boolG4RegionRequested; // variable used internally just to check that no new volume is defined after + // a G4Region has been requested - perhaps unnecessary check, but just to be on the safe side + +}; + +#endif diff --git a/include/musrPhysicsList.hh b/include/musrPhysicsList.hh new file mode 100644 index 0000000..570dc9b --- /dev/null +++ b/include/musrPhysicsList.hh @@ -0,0 +1,52 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#ifndef musrPhysicsList_h +#define musrPhysicsList_h 1 + +#include "G4VUserPhysicsList.hh" +#include "globals.hh" +//cks Added to have Geant default muon decay with spin +#include "G4DecayWithSpin.hh" +//#include "musrDecayWithSpin.hh" + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class musrPhysicsList: public G4VUserPhysicsList +{ + public: + musrPhysicsList(); + ~musrPhysicsList(); + + protected: + // Construct particle and physics + void ConstructParticle(); + void ConstructProcess(); + + void SetCuts(); + + + protected: + // these methods Construct particles + void ConstructBosons(); + void ConstructLeptons(); + void ConstructMesons(); + void ConstructBaryons(); + + protected: + // these methods Construct physics processes and register them + void ConstructGeneral(); + void ConstructEM(); + + private: + // char myProcesses[100]; + // G4String parameterFileName; // name of the file with the physics list defined + void ReportProblemWithProcessDefinition(char myString[501]); + G4Region* FindG4Region(G4String regionName, char* lineOfSteeringFile); + char eMessage[200]; +}; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#endif + + diff --git a/include/musrPrimaryGeneratorAction.hh b/include/musrPrimaryGeneratorAction.hh new file mode 100644 index 0000000..92680a8 --- /dev/null +++ b/include/musrPrimaryGeneratorAction.hh @@ -0,0 +1,108 @@ + +#ifndef musrPrimaryGeneratorAction_h +#define musrPrimaryGeneratorAction_h 1 + +#include "G4VUserPrimaryGeneratorAction.hh" +#include "globals.hh" +#include "Randomize.hh" +#include "G4ThreeVector.hh" +#include "G4ParticleDefinition.hh" +#include +#include + +class G4GeneralParticleSource; +class G4ParticleGun; +class G4Event; +class musrDetectorConstruction; +class musrPrimaryGeneratorMessenger; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... + +class musrPrimaryGeneratorAction : public G4VUserPrimaryGeneratorAction +{ + public: + musrPrimaryGeneratorAction(musrDetectorConstruction*); + ~musrPrimaryGeneratorAction(); + + public: + void GeneratePrimaries(G4Event*); + void SetRndmFlag(G4String val) { rndmFlag = val;} + void Setvertex(G4ThreeVector v) {x0=v[0]; y0=v[1]; z0=v[2];} + void SetvertexSigma(G4ThreeVector v) {xSigma=v[0]; ySigma=v[1]; zSigma=v[2];} + void SetvertexBoundary(G4ThreeVector v) {rMaxAllowed=v[0]; zMinAllowed=v[1]; zMaxAllowed=v[2];} + void SetKEnergy(G4double val); + void SetMomentum(G4double val) {p0=val;} + void SetMomentumSmearing(G4double val) {pSigma=val;} + void SetMomentumBoundary(G4ThreeVector v){pMinAllowed=v[0]; pMaxAllowed=v[1];} + void SetTilt(G4ThreeVector v) {xangle0=v[0]; yangle0=v[1];} + void SetSigmaTilt(G4ThreeVector v) {xangleSigma=v[0]; yangleSigma=v[1];} + void SetPitch(G4double val) {pitch=val;} + void SetInitialMuonPolariz(G4ThreeVector vIniPol); + void SetInitialPolarizFraction(G4double val) { + if ((val>1.)||(val<-1.)) { + G4cout<<"musrPrimaryGeneratorAction.hh: SetInitialPolarizFraction(): polarisation fraction out of range ("< * GetPointerToSeedVector(); + + G4double decaytime; + +private: + static std::vector * pointerToSeedVector; + +}; + +#endif + + diff --git a/include/musrPrimaryGeneratorMessenger.hh b/include/musrPrimaryGeneratorMessenger.hh new file mode 100644 index 0000000..5b0521e --- /dev/null +++ b/include/musrPrimaryGeneratorMessenger.hh @@ -0,0 +1,46 @@ +#ifndef musrPrimaryGeneratorMessenger_h +#define musrPrimaryGeneratorMessenger_h 1 + +#include "G4UImessenger.hh" +#include "globals.hh" + +class musrPrimaryGeneratorAction; +class G4UIcmdWithAString; +class G4UIcmdWithADoubleAndUnit; +class G4UIcmdWithADouble; +class G4UIcmdWithAnInteger; +class G4UIcmdWith3VectorAndUnit; +class G4UIcmdWith3Vector; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... + +class musrPrimaryGeneratorMessenger: public G4UImessenger +{ + public: + musrPrimaryGeneratorMessenger(musrPrimaryGeneratorAction*); + ~musrPrimaryGeneratorMessenger(); + + void SetNewValue(G4UIcommand*, G4String); + + private: + musrPrimaryGeneratorAction* musrAction; + G4UIcmdWith3VectorAndUnit* setvertexCmd; + G4UIcmdWith3VectorAndUnit* setvertexSigmaCmd; + G4UIcmdWith3VectorAndUnit* setvertexBoundaryCmd; + G4UIcmdWithADoubleAndUnit* setKEnergyCmd; + G4UIcmdWithADoubleAndUnit* setMomentumCmd; + G4UIcmdWithADoubleAndUnit* setMomentumSmearingCmd; + G4UIcmdWith3VectorAndUnit* setMomentumBoundaryCmd; + G4UIcmdWith3VectorAndUnit* setTiltAngleCmd; + G4UIcmdWith3VectorAndUnit* setSigmaTiltAngleCmd; + G4UIcmdWithADoubleAndUnit* setPitchCmd; + G4UIcmdWith3Vector* setMuonPolarizCmd; + G4UIcmdWithADouble* setMuonPolarizFractionCmd; + G4UIcmdWith3VectorAndUnit* setMuonDecayTimeCmd; + G4UIcmdWithAString* setTurtleCmd; + G4UIcmdWithADoubleAndUnit* setTurtleZ0Cmd; + G4UIcmdWith3Vector* setTurtleMomentumBite; + G4UIcmdWithAnInteger* setTurtleEventNrCmd; +}; +#endif + diff --git a/include/musrQuadrupole.hh b/include/musrQuadrupole.hh new file mode 100644 index 0000000..85b576b --- /dev/null +++ b/include/musrQuadrupole.hh @@ -0,0 +1,49 @@ +#ifndef musrQuadrupole_h +#define musrQuadrupole_h 1 + +#include "globals.hh" +#include "F04ElementField.hh" +#include "F04GlobalField.hh" +//#include "G4ios.hh" +#include "BLEngeFunction.hh" +//#include +//#include +//#include +const G4double FRINGE_ACCURACY=1.0e-4; + +class musrQuadrupole : public F04ElementField +{ +public: + musrQuadrupole(G4double halflengthVal, G4double fieldRadiusVal, G4double gradientVal, G4double fringeFactorVal, G4LogicalVolume* logVolume, G4ThreeVector positionOfTheCenter); + // musrQuadrupole is based on "BLCMDgenericquad" class of the G4beamline package. + // + + /// Destructor. + virtual ~musrQuadrupole() {} + + /// addFieldValue() adds the field for this solenoid into field[]. + /// point[] is in global coordinates. + void addFieldValue( const G4double Point[4], G4double* field) const; + + G4double GetNominalFieldValue(); + void SetNominalFieldValue(G4double newFieldValue); + + // getWidth(), getHeight(), getLength(), return the dimensions of the field + // (used to define the boundary of the field) + virtual G4double getWidth() { return 2*fieldRadius; } // x coordinate + virtual G4double getHeight() { return 2*fieldRadius; } // y coordinate + virtual G4double getLength() { return 2*fringeMaxZ; } //{ return 2*halflength; } // z coordinate + + +private: + G4double gradient; + G4double fieldRadius; + G4double halflength; + + G4double fringeMaxZ; + G4double fringeDepth; + + BLEngeFunction enge; +}; + +#endif diff --git a/include/musrRootOutput.hh b/include/musrRootOutput.hh new file mode 100644 index 0000000..1e178e0 --- /dev/null +++ b/include/musrRootOutput.hh @@ -0,0 +1,291 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#ifndef musrRootOutput_h +#define musrRootOutput_h 1 + +//#include "G4UserRunAction.hh" +#include "globals.hh" +#include "G4ThreeVector.hh" +// ROOT +#include "TFile.h" +#include "TTree.h" +#include "TH1.h" +#include "TH2.h" +#include "TVectorD.h" +// +#include +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class musrRootOutput { + public: + musrRootOutput(); + ~musrRootOutput(); + static musrRootOutput* GetRootInstance(); + + public: + void BeginOfRunAction(); + void EndOfRunAction(); + void FillEvent(); + void ClearAllRootVariables(); + void SetVolumeIDMapping(std::string logivol, int volumeID); + G4int ConvertVolumeToID(std::string logivol); + G4int ConvertProcessToID(std::string processName); + void SetSpecialSaveVolumeDefined() {boolIsAnySpecialSaveVolumeDefined=true;}; + + // Getting variables (just for debugging) + G4double GetDecayPositionZ() {return muDecayPosZ_t;}; + G4double GetDecayTime() {return muDecayTime_t*microsecond;}; + G4double GetTimeInTarget() {return muTargetTime_t*microsecond;}; + + // Setting variables common to the whole event: + void SetRunID (G4int id) {runID_t = id;}; + void SetEventID (G4int id) {eventID_t = id;}; + void SetDecayDetectorID (std::string detectorName) {muDecayDetID_t = SensDetectorMapping[detectorName];}; + void SetBField (G4double F[6]) {B_t[0]=F[0]/tesla; B_t[1]=F[1]/tesla; B_t[2]=F[2]/tesla; + B_t[3]=F[3]/tesla; B_t[4]=F[4]/tesla; B_t[5]=F[5]/tesla;}; + void SetDecayPolarisation (G4ThreeVector pol) {muDecayPolX_t=pol.x(); muDecayPolY_t=pol.y(); muDecayPolZ_t=pol.z();}; + void SetDecayPosition (G4ThreeVector pos) {muDecayPosX_t=pos.x()/mm; muDecayPosY_t=pos.y()/mm; + muDecayPosZ_t=pos.z()/mm;}; + void SetEventWeight (G4double w) {weight_t *= w;} + void SetDetectorInfo (G4int nDetectors, G4int ID, G4int particleID, G4double edep, + G4double edep_el, G4double edep_pos, + G4double edep_gam, G4double edep_mup,G4int nsteps, G4double length, G4double t1, + G4double t2, G4double x, G4double y, G4double z, + G4double ek, G4double ekVertex, G4double xVertex, G4double yVertex, G4double zVertex, + G4int idVolVertex, G4int idProcVertex, G4int idTrackVertex) ; + + void SetDetectorInfoVvv (G4int nDetectors, + G4double ekVertex, G4double xVertex, G4double yVertex, G4double zVertex, + G4int idVolVertex, G4int idProcVertex, G4int idTrackVertex, G4int particleID) ; + + void SetSaveDetectorInfo (G4int ID, G4int particleID, G4double ke, G4double x, G4double y, G4double z, + G4double px, G4double py, G4double pz) ; + + void SetInitialMuonParameters(G4double x, G4double y, G4double z, G4double px, G4double py, G4double pz, + G4double xpolaris, G4double ypolaris, G4double zpolaris) { + muIniPosX_t=x; muIniPosY_t=y; muIniPosZ_t=z; + muIniMomX_t=px; muIniMomY_t=py; muIniMomZ_t=pz; + muIniPolX_t=xpolaris; muIniPolY_t=ypolaris; muIniPolZ_t=zpolaris; + } + void PrintInitialMuonParameters() { + G4cout<<"musrRootOutput.hh: Initial muon parameters: x="< SensDetectorMapping; + std::map ProcessIDMapping; +}; + +#endif diff --git a/include/musrRunAction.hh b/include/musrRunAction.hh new file mode 100644 index 0000000..826bed4 --- /dev/null +++ b/include/musrRunAction.hh @@ -0,0 +1,36 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#ifndef musrRunAction_h +#define musrRunAction_h 1 + +#include "G4UserRunAction.hh" +#include "globals.hh" +#include "musrRootOutput.hh" + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class G4Timer; +class G4Run; + +class musrRunAction : public G4UserRunAction +{ + public: + musrRunAction(); + ~musrRunAction(); + + public: + void BeginOfRunAction(const G4Run*); + void EndOfRunAction(const G4Run*); + + private: + G4Timer* timer; +}; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#endif + + + + + diff --git a/include/musrScintHit.hh b/include/musrScintHit.hh new file mode 100644 index 0000000..9a9a606 --- /dev/null +++ b/include/musrScintHit.hh @@ -0,0 +1,139 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#ifndef musrScintHit_h +#define musrScintHit_h 1 + +#include "G4VHit.hh" +#include "G4THitsCollection.hh" +#include "G4Allocator.hh" +#include "G4ThreeVector.hh" +#include "G4MagneticField.hh" +#include "globals.hh" +#include "G4ios.hh" +// ROOT +#include "TFile.h" +#include "TTree.h" + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class musrScintHit : public G4VHit +{ + public: + + musrScintHit(); + ~musrScintHit(); + musrScintHit(const musrScintHit&); + const musrScintHit& operator=(const musrScintHit&); + G4int operator==(const musrScintHit&) const; + // bool operator() (musrScintHit hit1, musrScintHit hit2) { return (hit1.globalTime musrScintHitsCollection; + +extern G4Allocator musrScintHitAllocator; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +inline void* musrScintHit::operator new(size_t) +{ + void *aHit; + aHit = (void *) musrScintHitAllocator.MallocSingle(); + return aHit; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +inline void musrScintHit::operator delete(void *aHit) +{ + musrScintHitAllocator.FreeSingle((musrScintHit*) aHit); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#endif diff --git a/include/musrScintSD.hh b/include/musrScintSD.hh new file mode 100644 index 0000000..8b60aa2 --- /dev/null +++ b/include/musrScintSD.hh @@ -0,0 +1,38 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#ifndef musrScintSD_h +#define musrScintSD_h 1 + +#include "G4VSensitiveDetector.hh" +#include "musrScintHit.hh" +#include "musrRootOutput.hh" + +class G4Step; +class G4HCofThisEvent; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class musrScintSD : public G4VSensitiveDetector +{ + public: + musrScintSD(G4String); + ~musrScintSD(); + + void Initialize(G4HCofThisEvent*); + G4bool ProcessHits(G4Step*, G4TouchableHistory*); + void EndOfEvent(G4HCofThisEvent*); + + private: + musrScintHitsCollection* scintCollection; + G4bool myStoreOnlyEventsWithHits; + G4int myStoreOnlyEventsWithHitInDetID; + G4double mySignalSeparationTime; + G4bool myStoreOnlyTheFirstTimeHit; + G4bool boolIsVvvInfoRequested; + +}; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#endif + diff --git a/include/musrSteppingAction.hh b/include/musrSteppingAction.hh new file mode 100644 index 0000000..673d65a --- /dev/null +++ b/include/musrSteppingAction.hh @@ -0,0 +1,73 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#ifndef musrSteppingAction_h +#define musrSteppingAction_h 1 + +#include "G4UserSteppingAction.hh" +#include "G4ProcessManager.hh" +#include "globals.hh" +#include "musrRootOutput.hh" +#include + +class G4Timer; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class musrSteppingAction : public G4UserSteppingAction +{ + public: + + static musrSteppingAction* GetInstance(); + musrSteppingAction(); + ~musrSteppingAction(); + + void UserSteppingAction(const G4Step *theStep); + void DoAtTheBeginningOfEvent(); + void SetLogicalVolumeAsSpecialSaveVolume(G4String logicName, G4int volumeID); + void SetVolumeForMuonEventReweighting(G4String logicName, G4int weight); + G4bool GetInfoAboutOldTrack(G4int trackID, G4int& parentTrackID, G4int& particleID, G4double& vertexKine, + G4ThreeVector& vertexPosition, G4String& vertexLogVol, G4String& vertexProcess); + G4bool AreTracksCommingFromSameParent(G4int trackID1, G4int trackID2, G4String volumeName); + static const G4int maxNumberOfOldTracks=200; + G4bool IsVvvInfoRequested() {return boolIsVvvInfoRequested;} + void SetVvvInfoRequested(G4bool boolvar) {boolIsVvvInfoRequested = boolvar;} + void SetCalculationOfFieldIntegralRequested(G4bool decision) {boolCalculateFieldIntegral = decision;} + + private: + musrRootOutput* myRootOutput; + G4Timer* timer; + time_t realTimeWhenThisEventStarted; + static musrSteppingAction* pointer; + + G4bool muAlreadyWasInTargetInThisEvent; + G4bool muAlreadyWasInM0InThisEvent; + G4bool muAlreadyWasInM1InThisEvent; + G4bool muAlreadyWasInM2InThisEvent; + G4bool radioactiveElectronAlreadySavedInThisEvent; + G4bool boolIsAnySpecialSaveVolumeDefined; + G4bool boolIsVvvInfoRequested; + std::map saveVolumeMapping; + G4String lastActualVolume; + G4bool boolMuonEventReweighting; + G4bool boolCalculateFieldIntegral; + std::map volumeMuonWeightMapping; + + G4int indexOfOldTrack; + std::map myOldTracksMap; + G4int particleID_oldTrack[maxNumberOfOldTracks]; + G4int parentTrackID_oldTrack[maxNumberOfOldTracks]; + G4double vertexKine_oldTrack[maxNumberOfOldTracks]; + G4ThreeVector vertexPosition_oldTrack[maxNumberOfOldTracks]; + G4String vertexLogVol_oldTrack[maxNumberOfOldTracks]; + G4String vertexProcess_oldTrack[maxNumberOfOldTracks]; + + // for field integral along the muon path (if its calculation is requested by the user) + G4double BxIntegral, ByIntegral, BzIntegral; + G4double BzIntegral1, BzIntegral2, BzIntegral3; + G4double CoordinateForFieldIntegral[4]; + G4double FieldForFieldIntegral[6]; +}; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#endif diff --git a/include/musrSteppingVerbose.hh b/include/musrSteppingVerbose.hh new file mode 100644 index 0000000..034b97f --- /dev/null +++ b/include/musrSteppingVerbose.hh @@ -0,0 +1,26 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class musrSteppingVerbose; + +#ifndef musrSteppingVerbose_h +#define musrSteppingVerbose_h 1 + +#include "G4SteppingVerbose.hh" + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +class musrSteppingVerbose : public G4SteppingVerbose +{ + public: + + musrSteppingVerbose(); + ~musrSteppingVerbose(); + + void StepInfo(); + void TrackingStarted(); + +}; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#endif diff --git a/include/musrTabulatedElementField.hh b/include/musrTabulatedElementField.hh new file mode 100644 index 0000000..a1ee420 --- /dev/null +++ b/include/musrTabulatedElementField.hh @@ -0,0 +1,68 @@ +#ifndef musrTabulatedElementField_h +#define musrTabulatedElementField_h 1 + +#include "globals.hh" +#include "F04ElementField.hh" +#include "F04GlobalField.hh" +#include "G4ios.hh" +#include +#include +#include + + +class musrTabulatedElementField : public F04ElementField +{ +public: + musrTabulatedElementField(const char* filename, const char* fldTableType, G4double fieldValue, G4LogicalVolume* logVolume, G4ThreeVector positionOfTheCenter); + // "lenUnit" is the unit in which the grid coordinates are specified in the table + // "fieldNormalisation" is the normalisation that has to be applied on the field values in the table + // such that the values correspond do 1T nominal value + // "fieldValue" is the field value (in T) that is required (i.e. values normalised to 1T will be + // multiplied by this value). + + /// Destructor. + virtual ~musrTabulatedElementField() {} + + /// addFieldValue() adds the field for this solenoid into field[]. + /// point[] is in global coordinates. + void addFieldValue( const G4double Point[4], G4double* field) const; + void addFieldValue2D( const G4double Point[4], G4double* field) const; + void addFieldValue3D( const G4double Point[4], G4double* field) const; + + G4double GetNominalFieldValue(); + void SetNominalFieldValue(G4double newFieldValue); + + // getWidth(), getHeight(), getLength(), return the dimensions of the field + // (used to define the boundary of the field) + virtual G4double getWidth() {return maximumWidth;} // x coordinate + virtual G4double getHeight() {return maximumHeight;} // y coordinate + virtual G4double getLength() {return maximumLength;} // z coordinate + + +private: + // Storage space for the table + std::vector< std::vector< std::vector< double > > > xField; + std::vector< std::vector< std::vector< double > > > yField; + std::vector< std::vector< std::vector< double > > > zField; + std::vector< std::vector< double > > xField2D; + std::vector< std::vector< double > > zField2D; + // The dimensions of the table + int nx,ny,nz; + // The units of the field + char fieldTableType[100]; + G4String fUnit; + double fieUnit; + char fldType; + int fldDim; + // The physical limits of the defined region + double minimumx, maximumx, minimumy, maximumy, minimumz, maximumz; + // The physical extent of the defined region + double dx, dy, dz; + double ffieldValue; + double maximumWidth, maximumHeight, maximumLength; + + void Invert(const char* indexToInvert); + +}; + +#endif diff --git a/include/musrUniformField.hh b/include/musrUniformField.hh new file mode 100644 index 0000000..775106d --- /dev/null +++ b/include/musrUniformField.hh @@ -0,0 +1,45 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +#ifndef UNIFORM_BFIELD_HH +#define UNIFORM_BFIELD_HH +#include "G4LogicalVolume.hh" +#include "G4Box.hh" +#include "F04ElementField.hh" +#include "F04GlobalField.hh" + +// UniformField implements a constant electromagnetic field in any direction. TS + +class musrUniformField : public F04ElementField +{ + public: + + musrUniformField(G4double EMF[6], G4double half_X, G4double half_Y, G4double half_Z, G4LogicalVolume*, G4ThreeVector); + + virtual ~musrUniformField() {} + + // TS: Define the two newly added VIRTUAL functions of F04ElementField + G4double GetNominalFieldValue(); + void SetNominalFieldValue(G4double newFieldValue); + + virtual G4double getLength() { return fieldLength; } + virtual G4double getWidth() { return fieldWidth; } + virtual G4double getHeight() { return fieldHeight; } + + G4bool isOutside(G4ThreeVector& local) const; + G4bool isWithin (G4ThreeVector& local) const; + + void addFieldValue(const G4double point[4], G4double field[6]) const; + + private: + + G4double EMfield[6]; + + G4double fieldLength; + G4double fieldWidth; + G4double fieldHeight; +}; + +#endif diff --git a/include/yields.hh b/include/yields.hh new file mode 100644 index 0000000..1d7fe6c --- /dev/null +++ b/include/yields.hh @@ -0,0 +1,44 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +// Muonium yields as a function of initial mu+ energies. +// The method GetYields is used by MuFormation. +// Id : yields.cc, v 1.1 +// Author: Taofiq PARAISO, T. Shiroka +// Date : 2007-12 +// Notes : First implemented in Fortran by A. Hofer +// C++ conversion by T.K. Paraiso 04-2005 +// Slight modifications by T. Shiroka +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + +#ifndef Yields_h +#define Yield_h 1 + +#include "globals.hh" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + The Muonium Yield function as well as the parameters are taken from: + M. Gonin, R. Kallenbach, P. Bochsler: "Charge exchange of hydrogen atoms + in carbon foils at 0.4 - 120 keV", Rev.Sci.Instrum. 65 (3), March 1994 +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +class Yields +{ + +public: + Yields(); // Class constructor + ~Yields(); // Class destructor + + void GetYields(double E, double mass, double yvector[]); + +private: // Some internal variables + double Q_zero, Q_minus, D; + double Yield_minus, Yield_zero, Yield_plus; + + double aux1, aux2, aux3; // Auxiliary variables +}; + +#endif diff --git a/musrSim.cc b/musrSim.cc new file mode 100644 index 0000000..f736ce9 --- /dev/null +++ b/musrSim.cc @@ -0,0 +1,151 @@ +#include "musrDetectorConstruction.hh" +#include "musrPhysicsList.hh" +#include "musrPrimaryGeneratorAction.hh" +#include "musrRunAction.hh" +#include "musrEventAction.hh" +#include "musrSteppingAction.hh" +#include "musrSteppingVerbose.hh" + +#include "G4RunManager.hh" +#include "G4UImanager.hh" +#include "G4UIterminal.hh" +#include "G4UItcsh.hh" + +// The following two lines are needed to cope with the problem of +// "Error in : Cannot find plugin handler for TVirtualStreamerInfo! +// Does $ROOTSYS/etc/plugins/TVirtualStreamerInfo exist?" +#include "TROOT.h" +#include "TPluginManager.h" + +#include "Randomize.hh" + +#include + +#ifdef G4VIS_USE + // #include "musrVisManager.hh" + #include "G4VisExecutive.hh" + #include "G4TrajectoryDrawByCharge.hh" // TS Trajectory drawing by ID or charge +#endif + +#include "musrRootOutput.hh" +#include "musrParameters.hh" +#include "musrErrorMessage.hh" +//#include "F04GlobalField.hh" + +int main(int argc,char** argv) { + + XInitThreads(); + + // choose the Random engine + // CLHEP::HepRandom::setTheEngine(new CLHEP::RanecuEngine); // the /musr/run/randomOption 2 does not work with RanecuEngine + CLHEP::HepRandom::setTheEngine(new CLHEP::HepJamesRandom); + + //my Verbose output class + G4VSteppingVerbose::SetInstance(new musrSteppingVerbose); + + // Run manager + G4RunManager * runManager = new G4RunManager; + + // Create class "myParameters", which is a collection of many different parameters + G4String steeringFileName=argv[1]; + musrParameters* myParameters = new musrParameters(steeringFileName); + + // Create class "musrErrorMessage" + musrErrorMessage* myErrorMessage = new musrErrorMessage(); + + // Create Root class for storing the output of the Geant simulation + musrRootOutput* myRootOutput = new musrRootOutput(); + +// The following command is needed to cope with the problem of +// "Error in : Cannot find plugin handler for TVirtualStreamerInfo! +// Does $ROOTSYS/etc/plugins/TVirtualStreamerInfo exist?" +// /* magic line from Rene - for future reference! */ + gROOT->GetPluginManager()->AddHandler("TVirtualStreamerInfo", + "*", + "TStreamerInfo", + "RIO", + "TStreamerInfo()"); + + + // UserInitialization classes (mandatory) + musrDetectorConstruction* musrdetector = new musrDetectorConstruction; + if (argc>1) { + G4int myRunNr=atoi(argv[1]); // Get the run number from the name of the + // parameter file, if it starts with a number. + if (myRunNr>0) {runManager->SetRunIDCounter(myRunNr);} + musrdetector->SetInputParameterFileName(argv[1]); + } + runManager->SetUserInitialization(musrdetector); + runManager->SetUserInitialization(new musrPhysicsList); + +#ifdef G4VIS_USE + // Visualization, if you choose to have it! + // G4VisManager* visManager = new musrVisManager; + G4VisManager* visManager = new G4VisExecutive; // TS Trajectory drawing by ID or charge + visManager->Initialize(); +#endif + + // UserAction classes + runManager->SetUserAction(new musrPrimaryGeneratorAction(musrdetector)); + runManager->SetUserAction(new musrRunAction); + runManager->SetUserAction(new musrEventAction); + runManager->SetUserAction(new musrSteppingAction); + + //Initialize G4 kernel + runManager->Initialize(); + + //get the pointer to the User Interface manager + G4UImanager * UI = G4UImanager::GetUIpointer(); + + if(argc==1) + // Define (G)UI terminal for interactive mode + { + // G4UIterminal is a (dumb) terminal. + G4UIsession * session = 0; +#ifdef G4UI_USE_TCSH + session = new G4UIterminal(new G4UItcsh); +#else + session = new G4UIterminal(); +#endif + + UI->ApplyCommand("/control/execute vis.mac"); + session->SessionStart(); + delete session; + } + else + // Batch mode + { + G4String command = "/control/execute "; + G4String fileName = argv[1]; + UI->ApplyCommand(command+fileName); + if (argc>2) { + G4String SecondArgument = argv[2]; + if (SecondArgument=="idle") { + G4UIsession * session = 0; +#ifdef G4UI_USE_TCSH + session = new G4UIterminal(new G4UItcsh); +#else + session = new G4UIterminal(); +#endif + session->SessionStart(); + delete session; + } + } + } + +#ifdef G4VIS_USE + delete visManager; +#endif + delete myRootOutput; + delete myErrorMessage; + delete myParameters; + delete runManager; + + // F04GlobalField* myGlobalField = F04GlobalField::getObject(); + // if (myGlobalField!=NULL) {delete myGlobalField;} + + return 0; +} + + + diff --git a/run/1050.mac b/run/1050.mac new file mode 100644 index 0000000..2aef055 --- /dev/null +++ b/run/1050.mac @@ -0,0 +1,812 @@ +# Macro file for musr.cc - Construct detector, set fields and other parameters. +# Last modified by T. Shiroka: 17.03.2008 +# +# Corrected TD and MCP2 distances by T. Prokscha, 07.11.2008. +# + +# How to run: musr 10xx.mac (append "idle" for prompt after running) +# musr 10xx.mac > fname.txt (stores output on a txt file) +# +# Specify the geometry parameters in this file (all dimensions in mm) +# a. Lines starting with hash marks "#" are comments +# b Lines starting with #* are temporary comments. Remove/modify to change the configuration +# c. Lines starting with /musr/command are commands for the executable program +# d. Lines starting with /vis, /gun, etc. are common macro commands +# e. Beam-line components are ordered from exp. area (MCP2) to trigger detector (TD) +# +# Syntax example (following /musr/command): +# construct solid_type volume_name parameters_defining_solid material position mothers_name +# (mothers_name starts with log_) +# Examples +# +# Generate rotation matrix about n=(x,y,z) by th degrees +# /musr/command rotation MName x y z th +# +# Construct a volume +# /musr/command construct Type Name Material X Y Z MotherVolume RotationMatrix Sensitivity RootID [nofield] +# Type - can be tubs (cylindrical), box, sphere etc. +# Name - Just the name of the volume +# - Depend on the Type you are creating +# Material - Is the material in the volume, it can be G4_Galactic (vacuum), G4_PLASTIC_SC_VINYLTOLUENE (scintillator) etc. +# X Y Z - The position vector relative to the MotherVolume +# RotationMatrix - The rotation to be applied on the volume, it can be norot (no rotation) or other MName +# Sensitivity - If the volume has a respones, it can be musr/ScintSD (detector), dead (no response) +# RootID - An ID that will be saved in the root file for analysis +# nofield - Obsolete, should be removed. +# +# Uniform field in volume +# /musr/command globalfield FieldName half_x half_y half_z uniform X Y Z MotherVolume Bx By Bz Ex Ey Ez +# FieldName - A simple name for the field +# half_x half_y half_z - half lenghts of the box, within which the field is defined +# X Y Z - Position vector relative to MotherVolume +# MotherVolume - The volume containing the field +# Bx By Bz - Magnetic field vector +# Ex Ey Ez - Electric field vector +# +# Non-Uniform field according to a field map +# /musr/command globalfield FieldName X Y Z fromfile MapDim MapFileName.map MotherVolume ModBE +# FieldName - A simple name for the field +# X Y Z - Position vector relative to MotherVolume +# MotherVolume - The volume containing the field +# MapDim - Dimension and type of field, it can be 2DE (2D Electric), 2DB (2D Magnetic), 3DE (3D Electric) and 3DB (3D Magnetic) +# The 2D maps are propagated along the z axis to form the 3D map (to reduce the size of the map file) +# MapFileName.map - The field where the field map is stored +# ModBE - The size of the field (to scale the field map). +############################################################################################### + +# For the meaning of the acronyms see also the original G3 file ugeom.F at: +# http://savannah.psi.ch/viewcvs/trunk/simulation/geant3/src/lemsr/ugeom.F?root=nemu%2Flem&rev=2964&view=markup + +################################################################################################################ +# -- ROTATION MATRICES -- +################################################################################################################ + +# 3 parameters -> Define Euler angles (the 4th par. is set to zero). +# 4 parameters -> Define axis + rotation. +# HEP computations ordinarily use the active rotation viewpoint (object is rotated NOT axes). +# Therefore, rotations about an axis imply ACTIVE COUNTER-CLOCKWISE rotation in this package. +# Rotation around a specified axis means counter-clockwise rot. around the positive direction of the axis. + +# Define rotations for the field maps of Trigger and Ring Anode: +/musr/command rotation rotTrig 0 1 0 -45 +/musr/command rotation rotRAnR 0 0 1 -90 +/musr/command rotation rotRAnL 0 0 1 90 +/musr/command rotation rotRAnD 0 0 1 180 + +################################################################################################################ +# -- LEM GEOMETRY -- +################################################################################################################ + +# WORLD = Laboratory reference frame, the origin is in the centre of the LEM sample tube +/musr/command construct box World 250 250 2250 G4_Galactic 0 0 0 no_logical_volume norot dead -1 +# MINIMUM WORD HALF LENGTH 1250 mm! +#/musr/command construct box World 2000 2000 4000 G4_Galactic 0 0 0 no_logical_volume norot dead -1 + +# World visual attributes (optional) +/musr/command visattributes log_World invisible + + + + +#=============================================================================================================== +# Sc - Scintillators: U - up, D - down, L - left, R - right (with respect to muon's view - momentum direction) +# 8 Scintillators in two concentric rings - Inner and Outer (see also the convention for the Ring Anode) +#=============================================================================================================== + +## Inner Scintillators - I +/musr/command construct tubs ScIU 90 95 130 45 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 011 nofield +/musr/command construct tubs ScIR 90 95 130 135 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 012 nofield +/musr/command construct tubs ScID 90 95 130 225 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 013 nofield +/musr/command construct tubs ScIL 90 95 130 315 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 014 nofield + +## Outer Scintillators - O +/musr/command construct tubs ScOU 96 101 130 45 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 021 nofield +/musr/command construct tubs ScOR 96 101 130 135 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 022 nofield +/musr/command construct tubs ScOD 96 101 130 225 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 023 nofield +/musr/command construct tubs ScOL 96 101 130 315 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 024 nofield + +# Visual attributes (optional) +#*/musr/command visattributes log_ScOU SCINT_style +#*/musr/command visattributes log_ScOD dSCINT_style +/musr/command visattributes log_ScOL darkred +/musr/command visattributes log_ScIL darkred + + + +#=============================================================================================================== +# Experimental Area - Can host EITHER the Cryostat OR the MCP2 (For the tests we usually use the MCP) +# Delimited by the F160 and F100 (blank end) flanges +# +# 07/Nov/2008: correct sample tube dimensions: the new tubes have 75 mm / 78 mm inner/outer radius +# +#=============================================================================================================== + +# MCP - Multi-Channel Plate 2 Chamber; V - Vacuum, S - Solid # Note: VERY IMPORTANT: mcpv_z = -92.5 mm! +# OLD way of assigning a field +#/musr/command construct tubs MCPV 0 76.5 254.5 0 360 G4_Galactic 0 0 -92.5 log_World norot dead 100 MCPSfield +/musr/command construct tubs MCPV 0 75.0 254.5 0 360 G4_Galactic 0 0 -92.5 log_World norot dead 100 nofield +/musr/command construct tubs MCPS 75.0 78.0 162.0 0 360 Steel 0 0 0 log_World norot dead 101 nofield + +# F - Flanges: F160, F100, F200 (used only when the Asymmetry check is OFF) +# F160 - 160 CF flange upstream of MCP2 tube +# F100 (Blank end flange) # OLD Value was 162.0 +/musr/command construct tubs F160 78.0 101.25 11 0 360 Steel 0 0 -151.0 log_World norot dead 901 nofield +/musr/command construct tubs F100 0 75.0 10 0 360 Steel 0 0 172.0 log_World norot dead 902 nofield + +# NOTE: Original F100 referred to MCPV (as shown below) was moved to World. +#/musr/command construct tubs F100 0 76.5 10 0 360 Steel 0 0 264.5 log_MCPV norot dead 902 nofield + + +# Experimental Area visual attributes (optional) +/musr/command visattributes log_MCPV invisible +/musr/command visattributes log_MCPS invisible +/musr/command visattributes log_F160 blue_style +/musr/command visattributes log_F100 blue_style + + + + +#=============================================================================================================== +# MCP - Micro Channel Plate Detector MCP2 (Used as an alternative to cryostat) # mcpv_z = -92.5 mm! +# +# We have a 324 mm long sample tube; +# the MCP2 front side is at 142 mm from the end of the sample tube. +# the front face of the sample plate of the cryostat is 145 mm from the end of the sample tube. +# +#=============================================================================================================== + +# MCPM1 - MCP Macor ring 1 +# MCPD - electron multiplying glass disk (also known as target) +# Sensitive surface at z = 20 mm wrt. World +# MCPM2 - MCP Macor ring 2 +/musr/command construct tubs MCPM1 24 32.5 0.75 0 360 Macor 0 0 111.75 log_MCPV norot dead 201 nofield +# Use it either as (DMCP-musr/ScintSD) - no info on mu+ polariz., or as (target-dead) with info on mu+ polariz. +#*/musr/command construct tubs target 0 25.0 1.50 0 360 MCPglass 0 0 108.0 log_MCPV norot dead 032 nofield +/musr/command construct tubs MCPM2 24 32.5 0.75 0 360 Macor 0 0 116.25 log_MCPV norot dead 203 nofield +# NOTE: To intercept ALL the incoming muons, comment the DMCP and MCPM1 lines above and uncomment this one: +#*aa/musr/command construct tubs DMCP 0 76.5 1.5 0 360 MCPglass 0 0 108 log_MCPV norot musr/ScintSD 202 nofield +/musr/command construct tubs target 0 21.0 1.5 0 360 MCPglass 0 0 114 log_MCPV norot musr/ScintSD 202 nofield +/musr/command construct tubs saveTarget 0 75.0 0.2 0 360 G4_Galactic 0 0 110.79 log_MCPV norot dead 222 nofield + +# MCSR - Stainless Steel Ring for MCP2 mounting (modelled as a box with a circular hole) +# MCVR - "Vacuum Ring" (circular hole) +/musr/command construct box MCSR 36.5 36.5 1 Steel 0 0 118.5 log_MCPV norot dead 204 nofield +/musr/command construct tubs MCVR 0 27.5 1 0 360 G4_Galactic 0 0 0 log_MCSR norot dead 205 nofield + +# MCPA = MCP Anode (modelled as a box with two symmetrically subtracted "vacuum" disks) +# ANVA1 - Anode "Vacuum" 1 - Part of MCP Anode +# ANVA2 - Anode "Vacuum" 2 - Part of MCP Anode +/musr/command construct box MCPA 36.5 36.5 4 Steel 0 0 129.5 log_MCPV norot dead 206 nofield +/musr/command construct tubs ANVA1 0 27.5 1.5 0 360 G4_Galactic 0 0 -2.5 log_MCPA norot dead 207 nofield +/musr/command construct tubs ANVA2 0 27.5 1.5 0 360 G4_Galactic 0 0 2.5 log_MCPA norot dead 208 nofield + +# MCSS - MCP Stainless Steel Support Ring +/musr/command construct tubs MCSS 40 48 2.5 0 360 Steel 0 0 162.3 log_MCPV norot dead 209 nofield + + +# MCP2 visual attributes (optional) +#/musr/command visattributes log_DMCP MCP_style +#*/musr/command visattributes log_target MCP_style +#*/musr/command visattributes log_MCPM1 MACOR_style +#*------ /musr/command visattributes log_MCPM2 MACOR_style + + + + +#=============================================================================================================== +# CRY - Cryostat - Used as an ALTERNATIVE to MCP2 - Uncomment lines with #*. (Offset = 0.0 cm) +# +# at the moment, sample plate front face is still at z = 14.0mm --> should be changed to 17mm. +#=============================================================================================================== + +# SAH - SAmple Holder components (Cu plate) Cu or Al plates 1. Cu plate (sample holder) on Cold finger, 0.5cm +# SAPH - SAPpHire plate mounted between 1st and 2nd Cu plates, 6 mm thick, 60 mm diameter. +# SAH3 is ignored because currently NOT use. +#*/musr/command construct tubs SAH1 0 35 2.5 0 360 G4_Cu 0 0 119.0 log_MCPV norot dead 251 nofield +#*/musr/command construct tubs SAH2 0 35 2 0 360 G4_Cu 0 0 108.5 log_MCPV norot dead 252 nofield +#/musr/command construct tubs target 0 35 2 0 360 G4_Al 0 0 108.5 log_MCPV norot musr/ScintSD 252 nofield +#*/musr/command construct tubs saveTarget 0 44 0.2 0 360 G4_Galactic 0 0 106.29 log_MCPV norot dead 253 nofield +#/musr/command construct tubs SAH3 20 35 0.5 0 360 G4_Cu 0 0 106.0 log_MCPV norot dead 253 nofield +#*/musr/command construct tubs SAPH 0 30 3 0 360 G4_ALUMINUM_OXIDE 0 0 113.5 log_MCPV norot dead 254 nofield + +# Other components of the CRYostat (dimensions and position of CRY4 are only approx. because unknown) +# COFI - COld FInger +# CRY1 - End plate of cryostat (7 mm thick, 30 mm diameter) +# CRY2 - Heat exchanger (assuming a 10 mm opening - Original dimensions not known.) # OLD pos. 160.0 +# CRY3 - Mounting ring for He-shield +# CRY4 - 2 mm thick plate for mounting ring. This is just to close the downstream side. +# CRSH - Lateral He-shield +# CRSH2- Frontal He-shield Ring +#*/musr/command construct tubs COFI 0 27.5 5 0 360 G4_Cu 0 0 126.5 log_MCPV norot dead 261 nofield +#*/musr/command construct tubs CRY1 0 15 3.5 0 360 G4_Cu 0 0 135.0 log_MCPV norot dead 262 nofield +#*/musr/command construct tubs CRY2 5 15 25 0 360 G4_Cu 0 0 163.5 log_MCPV norot dead 263 nofield +#*/musr/command construct tubs CRY3 38 47 5.5 0 360 G4_Cu 0 0 143.5 log_MCPV norot dead 264 nofield +#*/musr/command construct tubs CRY4 15 38 1 0 360 G4_Cu 0 0 143.5 log_MCPV norot dead 265 nofield +#*/musr/command construct tubs CRSH 47 48 45 0 360 G4_Cu 0 0 108.5 log_MCPV norot dead 266 nofield +#*/musr/command construct tubs CRSH2 30 48 0.5 0 360 G4_Cu 0 0 63.0 log_MCPV norot dead 267 nofield + +# Electrical Field Guard Rings (distance between the guard rings: 16 mm) +#*/musr/command construct tubs Guard1 29 38 1.5 0 360 G4_Cu 0 0 76.0 log_MCPV norot dead 271 nofield +#*/musr/command construct tubs Guard2 29 38 1.5 0 360 G4_Cu 0 0 92.0 log_MCPV norot dead 272 nofield + + +# Cryostat visual attributes (optional) +#*/musr/command visattributes log_SAH1 oxsteel +#*/musr/command visattributes log_SAH2 oxsteel +#*/musr/command visattributes log_target oxsteel +#*/musr/command visattributes log_SAPH MACOR_style +#*/musr/command visattributes log_SAH3 oxsteel +#*/musr/command visattributes log_CRSH invisible + + + + +#=============================================================================================================== +# RA - Ring Anode, M - middle part (closer to Ground Anode), E - end part (farther from the Ground Anode) +# U - up, D - down, L - left, R - right (with respect to muon's view - momentum direction) +# Note: 3.0 mm HALF gap at 45.1469 mm half radius => delta_ang = asin(3.0/45.1469)*180/pi = 3.81 deg. +# Note: delta_ang = 3.1744 deg. for 2.5 mm HG. The angular extension goes e.g. from (45 + da) to (90 - 2*da). +# Note: Ring Anode - Ground Anode distance was 15 mm => CHANGED to 12 mm! (Positions: 11.5 -> 8.5, -33.5 -> -36.5) +#=============================================================================================================== + +# RA_Ez = -10.35+2.25 = -8.1 cm; RA_Mz= -10.35 - 2.25 = -12.6 cm; RA_Gz= -25.45+3.75 = -21.7 cm; mcpv_z = -9.25 cm +/musr/command construct cons RA_EU 45.1469 62.5 33.5 39.0 22.5 48.81 82.38 Steel 0 0 8.5 log_MCPV norot dead 301 nofield +/musr/command construct cons RA_MU 56.7937 62.5 45.147 62.5 22.5 48.81 82.38 Steel 0 0 -36.5 log_MCPV norot dead 302 nofield +/musr/command construct cons RA_ER 45.1469 62.5 33.5 39.0 22.5 48.81 82.38 Steel 0 0 8.5 log_MCPV rotRAnR dead 303 nofield +/musr/command construct cons RA_MR 56.7937 62.5 45.147 62.5 22.5 48.81 82.38 Steel 0 0 -36.5 log_MCPV rotRAnR dead 304 nofield +/musr/command construct cons RA_ED 45.1469 62.5 33.5 39.0 22.5 48.81 82.38 Steel 0 0 8.5 log_MCPV rotRAnD dead 305 nofield +/musr/command construct cons RA_MD 56.7937 62.5 45.147 62.5 22.5 48.81 82.38 Steel 0 0 -36.5 log_MCPV rotRAnD dead 306 nofield +/musr/command construct cons RA_EL 45.1469 62.5 33.5 39.0 22.5 48.81 82.38 Steel 0 0 8.5 log_MCPV rotRAnL dead 307 nofield +/musr/command construct cons RA_ML 56.7937 62.5 45.147 62.5 22.5 48.81 82.38 Steel 0 0 -36.5 log_MCPV rotRAnL dead 308 nofield + + +# Dummy, thin cylindres used for applying the SAME RA field-map (ROTATED by 90 deg.) to different anodes. +# NOTE: EM field cannot be applied to non simply connected bodies, as e.g. rings, cones, tori, etc.! +/musr/command construct tubs RA_U 0 0.01 0.005 0 360 G4_Galactic 0 0 -50.50 log_MCPV norot dead 322 nofield +/musr/command construct tubs RA_R 0 0.01 0.005 0 360 G4_Galactic 0 0 -50.52 log_MCPV rotRAnR dead 324 nofield +/musr/command construct tubs RA_D 0 0.01 0.005 0 360 G4_Galactic 0 0 -50.54 log_MCPV rotRAnD dead 326 nofield +/musr/command construct tubs RA_L 0 0.01 0.005 0 360 G4_Galactic 0 0 -50.56 log_MCPV rotRAnL dead 328 nofield + + +# RA_G - Ring Anode Ground Cylinder +/musr/command construct tubs RA_G 58 62.5 58.0 0 360 G4_Cu 0 0 -129.0 log_MCPV norot dead 351 nofield + + +# Ring Anodes visual attributes (optional) +/musr/command visattributes log_RA_EU oxsteel +/musr/command visattributes log_RA_MR oxsteel +/musr/command visattributes log_RA_G Grid_style + + +# Alternative placement using World as a mother volume (mcpv_z = -92.5 mm). Check latter. These values refer to a 5 mm GAP! +#/musr/command construct cons RA_EU 45.1469 62.5 33.5 39.0 22.5 48.1711 83.6578 Steel 0 0 -81 log_World norot dead 301 nofield +#/musr/command construct cons RA_MU 56.7937 62.5 45.147 62.5 22.5 48.1711 83.6578 Steel 0 0 -126 log_World norot dead 302 nofield + + + + +#=============================================================================================================== +# Gate Valve Area - Hosts the Ground Anode (upstream part of the Ring Anode) - Delimited by L3F1 and F200 flanges +#=============================================================================================================== + +# GATS - 200 CF flange upstream of MCP2 tube covering the whole length of the gate valve chamber. For simplicity, we +# choose the INNER diameter of the GATe valve Steel tube the same as the OUTER diameter of F200 (200 CF flange) +/musr/command construct tubs GATS 103.25 126.5 92.5 0 360 Steel 0 0 -254.5 log_World norot dead 371 nofield + +# Vacuum "Ring" (to avoid intersections with MCPV) - Not needed if world is already filled with vacuum. +#*/musr/command construct tubs GATV 76.5 103.25 92.5 0 360 G4_Galactic 0 0 -254.5 log_World norot dead 370 nofield + +# F200 - 200 CF flange upstream of MCP2 tube to connect to gate valve chamber +/musr/command construct tubs F200 76.5 103.25 12 0 360 Steel 0 0 -174.0 log_World norot dead 372 nofield + +# NOTE: When using GATV comment the F200 above and uncomment the following (change mother to log_GATV). +#*/musr/command construct tubs F200 76.5 103.25 12 0 360 Steel 0 0 80.5 log_GATV norot dead 372 nofield + + +# Gate Valve Area visual attributes (optional) +/musr/command visattributes log_GATS SCINT_style +/musr/command visattributes log_F200 blue_style + + + + +#=============================================================================================================== +# L3 - 3rd Einzel Lens # L3z = -56.7 cm. ATT: DUMMY FIELD change to electric L3Efield! +#=============================================================================================================== +# Lens Gap = 12.0 mm => G/D = 12/130 ~ 0.1 (Lens Gap = gap between Ground and Anode, D - Diameter) + +# L3 envelope (Tube + Flanges) +# L3VA - Lens 3 Vacuum +# L3ST - Lens 3 Steel tube (inner dia: 200 mm, outer dia: 206 mm, length: 720 mm) +# L3F1 - Lens 3 Flange 1, z = L3z + 208 mm +# L3F2 - Lens 3 Flange 2, z = L3z - 208 mm + +/musr/command construct tubs L3VA 0 100 220 0 360 G4_Galactic 0 0 -567 log_World norot dead 400 nofield +/musr/command construct tubs L3ST 100 103 220 0 360 Steel 0 0 -567 log_World norot dead 401 nofield +/musr/command construct tubs L3F1 103 126.5 12 0 360 Steel 0 0 -359 log_World norot dead 402 nofield +/musr/command construct tubs L3F2 103 126.5 12 0 360 Steel 0 0 -775 log_World norot dead 403 nofield + +# GPn - Ground Potential Electrodes +# n = 1-4 and 5-8 - components of the Ground Electrodes +# GP1 - Ground Electrode (inner dia: 130 mm, outer dia: 134 mm, length: 133 mm) +# GP2 - outer electrode surface (LN2 cooling vessel) +# GP3 - first ring cap +# GP4 - second ring cap + +# n = 1-4 - Ground Electrode 1 (further from TD). See above for the meaning of acronyms. +/musr/command construct tubs L3GP1 65 67 66.5 0 360 Steel 0 0 133.5 log_L3VA norot dead 421 nofield +/musr/command construct tubs L3GP2 81 83 66.5 0 360 Steel 0 0 133.5 log_L3VA norot dead 422 nofield +/musr/command construct tubs L3GP3 67 81 4 0 360 Steel 0 0 196.0 log_L3VA norot dead 423 nofield +/musr/command construct tubs L3GP4 67 81 4 0 360 Steel 0 0 71.0 log_L3VA norot dead 424 nofield + +# n = 5-8 - Ground Electrode 2 (closer to TD). See above for the meaning of acronyms. +/musr/command construct tubs L3GP5 65 67 66.5 0 360 Steel 0 0 -133.5 log_L3VA norot dead 431 nofield +/musr/command construct tubs L3GP6 81 83 66.5 0 360 Steel 0 0 -133.5 log_L3VA norot dead 432 nofield +/musr/command construct tubs L3GP7 67 81 4 0 360 Steel 0 0 -196.0 log_L3VA norot dead 433 nofield +/musr/command construct tubs L3GP8 67 81 4 0 360 Steel 0 0 -71.0 log_L3VA norot dead 434 nofield + +# HP - High Potential Electrode (Central Anode - usually at +8.7 kV, for a 15 keV muon beam) +/musr/command construct tubs L3HP 65 83 55 0 360 Steel 0 0 0 log_L3VA norot dead 451 nofield + + +# Lens 3 visual attributes (optional) +/musr/command visattributes log_L3VA invisible +/musr/command visattributes log_L3ST invisible +/musr/command visattributes log_L3HP darkred + + + + +#=============================================================================================================== +# IP - Intermediate Piece (between Trigger Detector and Einzel Lens 3) +# Original name was CGate - B-field Coil Compensation Gate?! # CompGatez = -86.55 cm; // L3z - 22 - 7.85 cm +#=============================================================================================================== +# IPV (but also others) are just empty volumes "filled" with vacuum. Sometimes used to apply EM fields to restricted areas. +/musr/command construct tubs IPV 0 100 78.5 0 360 G4_Galactic 0 0 -865.5 log_World norot dead 500 nofield +# IPCF - Intermediate Piece Central Flange (same as L3 Flanges) +# IPST - Intermediate Piece Steel Tube (same diameter as L3 Steel Tube) +/musr/command construct tubs IPCF 103 126.5 12.0 0 360 Steel 0 0 -865.5 log_World norot dead 501 nofield +/musr/command construct tubs IPST 100 103 78.5 0 360 Steel 0 0 -865.5 log_World norot dead 502 nofield + + +# IP visual attributes (optional) +/musr/command visattributes log_IPV invisible +/musr/command visattributes log_IPCF blue_style +/musr/command visattributes log_IPST gray + + + + +#=============================================================================================================== +# Trigger - Trigger Detector # Triggerz = -1092 mm; total length of TD is 110 mm; carbon foil at -1144 mm. +#=============================================================================================================== + +# Trigger tube and relative vacuum +/musr/command construct tubs TriggerV 0 100 148 0 360 G4_Galactic 0 0 -1092 log_World norot dead 600 nofield +/musr/command construct tubs Trigger 100 103 148 0 360 Steel 0 0 -1092 log_World norot dead 601 nofield + +# TF - Trigger tube flanges +/musr/command construct tubs TF1 103 126.5 12 0 360 Steel 0 0 -956 log_World norot dead 611 nofield +/musr/command construct tubs TF2 103 126.5 12 0 360 Steel 0 0 -1228 log_World norot dead 612 nofield + +#------------------------------------------------------------- +# trigger foil is 52mm upstream of Triggerz, i.e. at -1144 mm +#------------------------------------------------------------- +# Carbon Foil (default HALF-thickness 0.000005147 mm, see below => CFoil thick = 10.3 nm). +# USE THE NAME CFoil or coulombCFoil, otherwise musrMuFormation won't work! +####/musr/command construct box CFoil 60 60 0.000005147 G4_GRAPHITE 0 0 -45 log_TriggerV norot dead 621 nofield +/musr/command construct box CFoil 60 60 0.0000044 G4_GRAPHITE 0 0 -52.1 log_TriggerV norot dead 621 nofield +####/musr/command construct box coulombCFoil 60 60 0.000005147 G4_GRAPHITE 0 0 -45 log_TriggerV norot dead 621 nofield + +# Notes: NIST tables use G4_GRAPHITE with 1.7 g/cm3 and 78 eV ioniz. energy. +# An area density of 2.20 ug/cm2 implies a CF thickn. = (2.20*1.e-6/1.70)*cm = 1.294e-5 mm - Total thickness +# An area density of 1.75 ug/cm2 implies a CF thickn. = (1.75*1.e-6/1.70)*cm = 1.029e-5 mm - Total thickness +# If necessary, use Graphite as defined in musrDetectorConstruction.cc and set any density. + +# Dummy plane to intercept outgoing muons from the Carbon foil. +#*/musr/command construct box saveCFoil 60 60 5e-4 G4_Galactic 0 0 -52.0005 log_TriggerV norot dead 623 nofield +#*/musr/command construct box saveBeforeCFoil 60 60 5e-4 G4_Galactic 0 0 -52.105 log_TriggerV norot dead 623 nofield +#*/musr/command construct box saveAfterTD 60 60 5e-4 G4_Galactic 0 0 58.0006 log_TriggerV norot dead 623 nofield + + +# Electrical Field areas in the Trigger Detector +# En = Electrical Field n: TnFieldMgr (n = 1-3) +# Original TriggE2: [4.*sqrt(2), 4.5, 0.7/sqrt(2)] cm -> changed due to overlaps with E1 and E3 +/musr/command construct box TriggE0 45 45 5 G4_Galactic 0 0 -57.15 log_TriggerV norot dead 630 nofield +/musr/command construct box TriggE1 45 45 4 G4_Galactic 0 0 -48.0 log_TriggerV norot dead 631 nofield +/musr/command construct box TriggE2 45 45 4.9497 G4_Galactic 0 0 2.25 log_TriggerV rotTrig dead 632 nofield +/musr/command construct box TriggE3 45 45 4 G4_Galactic 0 0 54.0 log_TriggerV norot dead 633 + +# Beam spot (just for having a visual idea!) +/musr/command construct tubs BSpot 0 20 1 0 360 G4_Galactic 0 0 -63.15 log_TriggerV norot dead 650 nofield + + +# Trigger visual attributes (optional) +/musr/command visattributes log_TriggerV invisible +/musr/command visattributes log_Trigger invisible +/musr/command visattributes saveCFoil invisible +# Bug: It seems that if you set this to invisible the program stops. I see no reason for that! +#/musr/command visattributes log_saveAfterTD invisible +/musr/command visattributes log_BSpot invisible +#*/musr/command visattributes saveCFoil MACOR_style +#*/musr/command visattributes log_saveAfterTD darkred +/musr/command visattributes log_BSpot darkred + +# One can set visible attrib. also on a MATERIAL basis, rather than on log_VOL. +# E.g. /musr/command visattributes Steel red + + + + + +################################################################################################################ +# -- Setting the ELECTRIC and MAGNETIC fields -- +################################################################################################################ + +# Use ABSOLUTE coordinates to specify the field position (i.e. with respect to GLOBAL WORLD)! +# Default field units: Magnetic - T, Electric - kV/mm (or kV for E-field maps). +# NOTE: Applying a field to an invisible log_vol makes is visible! + +### Electric field at TRIGGER Detector TD: Three different uniform fields +/musr/command globalfield Trigg0_field 45 45 5 uniform 0. 0. -1149.15 log_TriggE0 0 0 0 0 0 0.373 +/musr/command globalfield Trigg1_field 45 45 4 uniform 0. 0. -1140. log_TriggE1 0 0 0 0 0 -0.02375 +/musr/command globalfield Trigg2_field 45 45 4.9497 uniform 0. 0. -1089.75 log_TriggE2 0 0 0 0 0 0.041416 +/musr/command globalfield Trigg3_field 45 45 4 uniform 0. 0. -1038.0 log_TriggE3 0 0 0 0 0 -0.49375 + + +### Electric field at Einzel LENS 3 - from folded 2D axial field map (f - folded, i.e. symmetric) +# Typically V = +8.7 kV for a muon beam at 15 keV. Use either 2DE L3_Erz.map or +# +# ATTENTION: The electric field is ANTI-symmetric: DO NOT use folded field map L3_Erz4.map!! +# +/musr/command globalfield Lens3_field 0. 0. -567. fromfile 2DE L3_Erz.map log_L3VA 8.352 +# To change the field in regular steps (e.g. for testing) use (f_min f_max step_no), e.g.: +#*/musr/command globalfield Lens3_field 0. 0. -567. fromfile 2DE L3_Erz.map log_L3VA 7 11 5 + + +### Electric field at RING ANODE - from 3DE field map +# Typically set at +11.0 kV for a muon beam at 15 keV +# To create an arbitrary configuration, switch on all fields and set different potentials. +#######/musr/command globalfield RngAnU_field 0. 0. -167.00 fromfile 3DE EM_3D_extc.map log_RA_U 11.0 +/musr/command globalfield RngAnL_field 0. 0. -143.06 fromfile 3DE EM_3D_ext_gridf.map log_RA_L 10.145 +/musr/command globalfield RngAnR_field 0. 0. -143.02 fromfile 3DE EM_3D_ext_gridf.map log_RA_R 10.955 +/musr/command globalfield RngAnU_field 0. 0. -143.00 fromfile 3DE EM_3D_ext_gridf.map log_RA_U 10.560 +/musr/command globalfield RngAnD_field 0. 0. -143.04 fromfile 3DE EM_3D_ext_gridf.map log_RA_D 10.569 + +### LAST FIELD OK: EM_3D_ext2f.map +# EXTENDED MAPS (from -28 to +20 mm) EM_3D_extc.map or EM_3D_extf.map (coord + field or field only) +# "Best" results with EM_RA_3D.map, even though this is not a precise map (poor meshing). +#RA_1kV_upf_raw.map +#RA_1kV_upf.map # EM_extendf2.map give rise to "strange spots" -> lem4_1047_RA13.eps + +### Electric field at SAMPLE space. Three possible field maps: Sample, G1 and G2 (closest to sample) +# To create an arbitrary configuration, switch on all fields and set different potentials. +# Field extension along z: 50 mm. Center of MCPV at z = -92.5 mm. Sample face at: z = 108.5 (4 mm thick - SAH2). +# Position of the field: (-92.5 - 50/2) + (108.5 - 4/2) = -11 mm wrt. WORLD! => +#*/musr/command globalfield Sample_field 0. 0. -11.0 fromfile 2DE sample_Erz.map log_MCPV 9.0 +#*/musr/command globalfield Guard2_field 0. 0. -11.0 fromfile 2DE guard2_Erz.map log_MCPV 6.0 +#*/musr/command globalfield Guard1_field 0. 0. -11.0 fromfile 2DE guard1_Erz.map log_MCPV 3.0 + + +### Magnetic field at SAMPLE space (use either a uniform field or a field map). +# Use either DMCP or MCPV to apply a CONSTANT field strictly to the sample or also to the surroundings, resp.! +#*/musr/command globalfield Magnet_field ? ? ? uniform 0. 0. 14.5 log_DMCP 0 0.005 0 0 0 0 +# Use field map to set field to 20 G TF +# Extended map has -100/100 cm z extension, field center at +70, original -85/85, center at +85 +#######/musr/command globalfield Magnet_field 0. 0. -836.0 fromfile 2DB sample_Brz.map log_IPV 0.002 +#*/musr/command globalfield Magnet_field 0. 0. -686.0 fromfile 2DB sample_Brz_ext.map log_L3VA 0.002 + + +# Set parameters for particle tracking in an EM field +/musr/command globalfield setparameter SetLargestAcceptableStep 5 +/musr/command globalfield setparameter SetMinimumEpsilonStep 5e-5 +/musr/command globalfield setparameter SetMaximumEpsilonStep 0.001 +/musr/command globalfield setparameter SetDeltaOneStep 0.1 +/musr/command globalfield setparameter SetDeltaIntersection 0.01 +/musr/command globalfield printparameters + + + + +################################################################################################################ +# -- Testing the ELECTRIC and MAGNETIC fields (OPTIONAL) -- +################################################################################################################ + +# FIELD CHECKS at different beam transport components (from trigg. to sample) +# All distances in mm and in GLOBAL coordinates (preferably at field center) +# The test points below are just some examples. Any point can be checked. + +# Trigger 0 +/musr/command globalfield printFieldValueAtPoint 0. 0. -1149.15 + +# Trigger 1 +/musr/command globalfield printFieldValueAtPoint 0. 0. -1140. +# Trigger 2 +/musr/command globalfield printFieldValueAtPoint 0. 0. -1089.75 +# Trigger 3 +/musr/command globalfield printFieldValueAtPoint 0. 0. -1038.0 + +# Einzel Lens 3 - L3 (center at -567.0, but max field at rel. +/-62 mm) +/musr/command globalfield printFieldValueAtPoint 0. 0. -507.0 + +# Ring Anode - RA (center at -167.0, but max field at rel. -16/+132 mm) +/musr/command globalfield printFieldValueAtPoint 0. 0. -35.0 + +# Sample space (center at -11.0, but max field at rel. +24 mm) +/musr/command globalfield printFieldValueAtPoint 0. 0. 13.0 + +# Check magnetic field at sample space +#*/musr/command globalfield printFieldValueAtPoint 10. 0. 13.0 +# Check magnetic field at the lower field end limit +#*/musr/command globalfield printFieldValueAtPoint 0. 20. -1680. + + + +################################################################################### +######################### P H Y S I C S P R O C E S S E S ################## +################################################################################### +# --- Low Energy (default) --- +/musr/command process addDiscreteProcess gamma G4LowEnergyPhotoElectric +/musr/command process addDiscreteProcess gamma G4LowEnergyCompton +/musr/command process addDiscreteProcess gamma G4LowEnergyGammaConversion +/musr/command process addDiscreteProcess gamma G4LowEnergyRayleigh +/musr/command process addProcess e- G4MultipleScattering -1 1 1 +#/musr/command process addDiscreteProcess e- G4CoulombScattering +/musr/command process addProcess e- G4LowEnergyIonisation -1 2 2 +/musr/command process addProcess e- G4LowEnergyBremsstrahlung -1 -1 3 +/musr/command process addProcess e+ G4MultipleScattering -1 1 1 +#/musr/command process addDiscreteProcess e+ G4CoulombScattering +/musr/command process addProcess e+ G4eIonisation -1 2 2 +/musr/command process addProcess e+ G4eBremsstrahlung -1 3 3 +/musr/command process addProcess e+ G4eplusAnnihilation 0 -1 4 +# +# --- High Energy --- +#/musr/command process addDiscreteProcess gamma G4PhotoElectricEffect +#/musr/command process addDiscreteProcess gamma G4ComptonScattering +#/musr/command process addDiscreteProcess gamma G4GammaConversion +#/musr/command process addProcess e- G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e- G4CoulombScattering +#/musr/command process addProcess e- G4eIonisation -1 2 2 +#/musr/command process addProcess e- G4eBremsstrahlung -1 3 3 +#/musr/command process addProcess e+ G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e+ G4CoulombScattering +#/musr/command process addProcess e+ G4eIonisation -1 2 2 +#/musr/command process addProcess e+ G4eBremsstrahlung -1 3 3 +#/musr/command process addProcess e+ G4eplusAnnihilation 0 -1 4 +# +# --- Penelope --- +#/musr/command process addDiscreteProcess gamma G4PenelopePhotoElectric +#/musr/command process addDiscreteProcess gamma G4PenelopeCompton +#/musr/command process addDiscreteProcess gamma G4PenelopeGammaConversion +#/musr/command process addDiscreteProcess gamma G4PenelopeRayleigh +#/musr/command process addProcess e- G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e- G4CoulombScattering +#/musr/command process addProcess e- G4PenelopeIonisation -1 2 2 +#/musr/command process addProcess e- G4PenelopeBremsstrahlung -1 -1 3 +#/musr/command process addProcess e+ G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e+ G4CoulombScattering +#/musr/command process addProcess e+ G4PenelopeIonisation, -1 2 2 +#/musr/command process addProcess e+ G4PenelopeBremsstrahlung, -1 -1 3 +#/musr/command process addProcess e+ G4PenelopeAnnihilation, 0 -1 4 +# +# --- Muons --- +/musr/command process addProcess mu+ G4MultipleScattering -1 1 1 +#/musr/command process addProcess mu+ MultipleAndCoulombScattering -1 1 1 goulombRegion +#/musr/command process addDiscreteProcess mu+ G4CoulombScattering +/musr/command process addProcess mu+ G4MuIonisation -1 2 2 +/musr/command process addProcess mu+ G4MuBremsstrahlung -1 3 3 +/musr/command process addProcess mu+ G4MuPairProduction -1 4 4 +/musr/command process addProcess mu- G4MultipleScattering -1 1 1 +#/musr/command process addDiscreteProcess mu- G4CoulombScattering +/musr/command process addProcess mu- G4MuIonisation -1 2 2 +/musr/command process addProcess mu- G4MuBremsstrahlung -1 3 3 +/musr/command process addProcess mu- G4MuPairProduction -1 4 4 +# --- Muonium --- +/musr/command process addProcess mu+ musrMuFormation -1 -1 2 +#cks - the following line not supported yet, has to be tested (at the moment, musrMuScatter is hard wired in the musrPhysicsList.cc): +#/musr/command process addProcess Mu musrMuScatter -1 -1 1 +################################################################################### +######################### R O O T O U T P U T ############################## +################################################################################### +#/musr/command rootOutput runID off +#/musr/command rootOutput eventID off +#/musr/command rootOutput weight off +#/musr/command rootOutput BFieldAtDecay off +#/musr/command rootOutput muIniPosX off +#/musr/command rootOutput muIniPosY off +#/musr/command rootOutput muIniPosZ off +#/musr/command rootOutput muIniMomX off +#/musr/command rootOutput muIniMomY off +#/musr/command rootOutput muIniMomZ off +#/musr/command rootOutput muIniPolX off +#/musr/command rootOutput muIniPolY off +#/musr/command rootOutput muIniPolZ off +#/musr/command rootOutput muDecayDetID off +#/musr/command rootOutput muDecayPosX off +#/musr/command rootOutput muDecayPosY off +#/musr/command rootOutput muDecayPosZ off +#/musr/command rootOutput muDecayTime off +#/musr/command rootOutput muDecayPolX off +#/musr/command rootOutput muDecayPolY off +#/musr/command rootOutput muDecayPolZ off +#/musr/command rootOutput muTargetTime off +#/musr/command rootOutput muTargetPolX off +#/musr/command rootOutput muTargetPolY off +#/musr/command rootOutput muTargetPolZ off +#/musr/command rootOutput muM0Time off +#/musr/command rootOutput muM0PolX off +#/musr/command rootOutput muM0PolY off +#/musr/command rootOutput muM0PolZ off +/musr/command rootOutput muM1Time off +/musr/command rootOutput muM1PolX off +/musr/command rootOutput muM1PolY off +/musr/command rootOutput muM1PolZ off +/musr/command rootOutput muM2Time off +/musr/command rootOutput muM2PolX off +/musr/command rootOutput muM2PolY off +/musr/command rootOutput muM2PolZ off +#/musr/command rootOutput posIniMomX off +#/musr/command rootOutput posIniMomY off +#/musr/command rootOutput posIniMomZ off +#/musr/command rootOutput fieldNomVal off +#/musr/command rootOutput det_ID off +#/musr/command rootOutput det_edep off +#/musr/command rootOutput det_edep_el off +#/musr/command rootOutput det_edep_pos off +#/musr/command rootOutput det_edep_gam off +#/musr/command rootOutput det_edep_mup off +#/musr/command rootOutput det_nsteps off +#/musr/command rootOutput det_length off +#/musr/command rootOutput det_start off +#/musr/command rootOutput det_end off +#/musr/command rootOutput det_x off +#/musr/command rootOutput det_y off +#/musr/command rootOutput det_z off +#/musr/command rootOutput det_kine off +/musr/command rootOutput det_VrtxKine off +/musr/command rootOutput det_VrtxX off +/musr/command rootOutput det_VrtxY off +/musr/command rootOutput det_VrtxZ off +/musr/command rootOutput det_VrtxVolID off +/musr/command rootOutput det_VrtxProcID off +/musr/command rootOutput det_VrtxTrackID off +/musr/command rootOutput det_VrtxParticleID off +/musr/command rootOutput det_VvvKine off +/musr/command rootOutput det_VvvX off +/musr/command rootOutput det_VvvY off +/musr/command rootOutput det_VvvZ off +/musr/command rootOutput det_VvvVolID off +/musr/command rootOutput det_VvvProcID off +/musr/command rootOutput det_VvvTrackID off +/musr/command rootOutput det_VvvParticleID off +### Root variables that are not written out by default, but can be switched on: +#/musr/command rootOutput fieldIntegralBx on +#/musr/command rootOutput fieldIntegralBy on +#/musr/command rootOutput fieldIntegralBz on +#/musr/command rootOutput fieldIntegralBz1 on +#/musr/command rootOutput fieldIntegralBz2 on +#/musr/command rootOutput fieldIntegralBz3 on +# +################################################################################################################ +# -- Setting simulation PARAMETERS -- +################################################################################################################ + +# Set the overall range cut (default 0.1 mm) +#*/run/setCut 1 mm + +# Set the range cut on particular volumes (in mm) +#/musr/command SetUserLimits log_CFoil 1e-8 -1 -1 -1 -1 +#*/musr/command SetUserLimits log_target 0.01 -1 -1 -1 -1 +#*/musr/command SetUserLimits log_targetscint 0.01 -1 -1 -1 -1 +#*/musr/command SetUserLimits log_cryostatscint 0.01 -1 -1 -1 -1 + +# Set particle energy cuts on particular volumes (in MeV) +#/musr/command SetUserLimits log_World ustepMax(mm) utrakMax(mm) utimeMax(ns) uekinMin(MeV) urangMin(mm) +/musr/command SetUserLimits log_World -1 -1 -1 1e-7 -1 + +# Store ALL the events in a ROOT tree or just the interesting ones? (default is true) +#*/musr/command storeOnlyEventsWithHits false + +# Set the minimum time separation between two subsequent signals in the same detector (in ns) +/musr/command signalSeparationTime 0.1 + +# Override runID number +#*/musr/run/runID 21 + +# Set the frequency of event printing +/musr/run/howOftenToPrintEvent 1000 + +# RANDOM option choices: (specify the random number generator initialisation) +# 0 ... no initialisation (default) +# 1 ... use actual computer time to initialise now +# 2 ... use event number to initialise at the beginning of each event +# 3 ... read in the random no. initial values for each event from a file +/musr/run/randomOption 2 + +# VISUALIZATION options +# To enable or disable visualization uncomment one of these lines +# To modify visualization options edit the file vis.mac +/vis/disable +#*/control/execute vis.mac + + + + + +################################################################################################################ +# -- Setting PARTICLE GUN parameters -- +################################################################################################################ + +# Default momentum direction: 001, i.e. 0z. +# Default muon spin direction: 100, i.e. 0x. +# Default particle type: mu+ (can be changed to Mu) + +# Set particle type +#*/gun/particle Mu +/gun/particle mu+ + +# Set beam vertex +# CFoil at -1144 mm, acceleration starts at -1154.15 mm +/gun/vertex 0. 0. -1155. mm + +# A point-like uniform beam +#/gun/vertexsigma -0.1 -0.1 0 mm + +# Set beam transverse spread (default GAUSSIAN spread) +# If FWHM = 10 mm ==> sigma = 10/2.354 = 4.2481 mm (last 0 is a dummy value) +# Negative sigma values => random FLAT RECTANGULAR distribution (area 2x.2y) +# Use vertexboundary with (vb < sigma_xy) to obtain a CIRCULAR beam spot +# /gun/vertexsigma 0 0 0 mm ==> Very SLOW with mag. field ON and centered beam +#*/gun/vertexsigma 42.5 42.5 0 mm +/gun/vertexsigma -20 -20 0 mm +/gun/vertexboundary 20 -1e6 1e6 mm + +# /gun/vertexboundary: rMaxAllowed, zMinAllowed, zMaxAllowed # Beam AND gating +#*/gun/vertexboundary 7 -1314.4 -1305 mm +# Without restrictions in z, but only on r: +#*/gun/vertexboundary 3 -1e6 1e6 mm + +# Set beam momentum (USE only as an ALTERNATIVE to setting energy!) +# /gun/momentum 0 0 29.79 MeV +#*/gun/momentum 0 0 1.8 MeV +# Energy loss at p = 1.2 MeV/c (E = 6.8 keV) => 1.23 +/- 0.2 keV +# Energy loss at p = 1.8 MeV/c (E = 15.3 keV) => 1.25 +/- 0.3 keV +# 1.2 MeV/c -> 6.8 keV, 1.8 MeV/c -> 15.3 keV +# muon rest mass = 105.658 MeV/c2 + +# Set muon energy before hitting TD; a constant field in front of the C-foil accelerates the muons +# to add 3.73 keV +/gun/kenergy 15.0 keV + +# Set beam momentum direction +/gun/direction 0.0 0.0 1.0 + +# Set muon spin direction +/gun/muonPolarizVector 1 0 0 + + +# Other useful test parameters: +# +# FWHM = 3% ==> sigma = 29.79*0.03/2.354 = 0.37965 MeV/c +#*/gun/momentumsmearing 0.37965 MeV +#---/gun/momentumboundary: pMinAllowed, pMaxAllowed, dummy +#*/gun/momentumboundary 20 40 0 MeV +#---/gun/tilt: xangle, yangle, dummy +#*/gun/tilt 0 0.5 0 deg +#---/gun/tiltsigma: xangleSigma, yangleSigma, dummy (1 degree at 1 m => 17 mm) +#*/gun/tiltsigma 0.2 0.2 0 deg +#*/gun/pitch 0.5 deg +#---/gun/decaytimelimits: decayMin, decayMax, decayTime +#*/gun/decaytimelimits 10400 10420 2197.03 ns + +# Selectively inactivate or activate sensitive detectors +#*/hits/inactivate /musr/ScintSD + +# Only for code debugging! +#/tracking/verbose 1 + +# BEAM ON +#*/run/beamOn 1000000 +#*/run/beamOn 2 +/run/beamOn 1000 + diff --git a/run/1050_old_version_WILL_NOT_RUN_WITH_musrSim.mac b/run/1050_old_version_WILL_NOT_RUN_WITH_musrSim.mac new file mode 100644 index 0000000..981ee5b --- /dev/null +++ b/run/1050_old_version_WILL_NOT_RUN_WITH_musrSim.mac @@ -0,0 +1,697 @@ +# Macro file for musr.cc - Construct detector, set fields and other parameters. +# Last modified by T. Shiroka: 17.03.2008 +# +# Corrected TD and MCP2 distances by T. Prokscha, 07.11.2008. +# + +# How to run: musr 10xx.mac (append "idle" for prompt after running) +# musr 10xx.mac > fname.txt (stores output on a txt file) + +############################################################################################### +# # +# Specify the geometry parameters in this file (all dimensions in mm) # +# a. Lines starting with hash marks "#" are comments # +# b Lines starting with #* are temporary comments. Remove/modify to change the configuration # +# c. Lines starting with /musr/command are commands for the executable program # +# d. Lines starting with /vis, /gun, etc. are common macro commands # +# e. Beam-line components are ordered from exp. area (MCP2) to trigger detector (TD) # +#---------------------------------------------------------------------------------------------# +# Syntax example (following /musr/command): # +# construct solid_type volume_name parameters_defining_solid material position mothers_name # +# (mothers_name starts with log_) # +############################################################################################### + +# For the meaning of the acronyms see also the original G3 file ugeom.F at: +# http://savannah.psi.ch/viewcvs/trunk/simulation/geant3/src/lemsr/ugeom.F?root=nemu%2Flem&rev=2964&view=markup + + + + + +################################################################################################################ +# -- ROTATION MATRICES -- +################################################################################################################ + +# 3 parameters -> Define Euler angles (the 4th par. is set to zero). +# 4 parameters -> Define axis + rotation. +# HEP computations ordinarily use the active rotation viewpoint (object is rotated NOT axes). +# Therefore, rotations about an axis imply ACTIVE COUNTER-CLOCKWISE rotation in this package. +# Rotation around a specified axis means counter-clockwise rot. around the positive direction of the axis. + +# Define rotations for the field maps of Trigger and Ring Anode: +/musr/command rotation rotTrig 0 1 0 -45 +/musr/command rotation rotRAnR 0 0 1 -90 +/musr/command rotation rotRAnL 0 0 1 90 +/musr/command rotation rotRAnD 0 0 1 180 + + + + + +################################################################################################################ +# -- LEM GEOMETRY -- +################################################################################################################ + +# WORLD = Laboratory reference frame, the origin is in the centre of the LEM sample tube +/musr/command construct box World 250 250 2250 G4_Galactic 0 0 0 no_logical_volume norot dead -1 +# MINIMUM WORD HALF LENGTH 1250 mm! +#/musr/command construct box World 2000 2000 4000 G4_Galactic 0 0 0 no_logical_volume norot dead -1 + +# World visual attributes (optional) +/musr/command visattributes log_World invisible + + + + +#=============================================================================================================== +# Sc - Scintillators: U - up, D - down, L - left, R - right (with respect to muon's view - momentum direction) +# 8 Scintillators in two concentric rings - Inner and Outer (see also the convention for the Ring Anode) +#=============================================================================================================== + +## Inner Scintillators - I +/musr/command construct tubs ScIU 90 95 130 45 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 011 nofield +/musr/command construct tubs ScIR 90 95 130 135 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 012 nofield +/musr/command construct tubs ScID 90 95 130 225 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 013 nofield +/musr/command construct tubs ScIL 90 95 130 315 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 014 nofield + +## Outer Scintillators - O +/musr/command construct tubs ScOU 96 101 130 45 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 021 nofield +/musr/command construct tubs ScOR 96 101 130 135 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 022 nofield +/musr/command construct tubs ScOD 96 101 130 225 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 023 nofield +/musr/command construct tubs ScOL 96 101 130 315 90 G4_PLASTIC_SC_VINYLTOLUENE 0 0 0 log_World norot musr/ScintSD 024 nofield + +# Visual attributes (optional) +#*/musr/command visattributes log_ScOU SCINT_style +#*/musr/command visattributes log_ScOD dSCINT_style +/musr/command visattributes log_ScOL darkred +/musr/command visattributes log_ScIL darkred + + + +#=============================================================================================================== +# Experimental Area - Can host EITHER the Cryostat OR the MCP2 (For the tests we usually use the MCP) +# Delimited by the F160 and F100 (blank end) flanges +# +# 07/Nov/2008: correct sample tube dimensions: the new tubes have 75 mm / 78 mm inner/outer radius +# +#=============================================================================================================== + +# MCP - Multi-Channel Plate 2 Chamber; V - Vacuum, S - Solid # Note: VERY IMPORTANT: mcpv_z = -92.5 mm! +# OLD way of assigning a field +#/musr/command construct tubs MCPV 0 76.5 254.5 0 360 G4_Galactic 0 0 -92.5 log_World norot dead 100 MCPSfield +/musr/command construct tubs MCPV 0 75.0 254.5 0 360 G4_Galactic 0 0 -92.5 log_World norot dead 100 nofield +/musr/command construct tubs MCPS 75.0 78.0 162.0 0 360 Steel 0 0 0 log_World norot dead 101 nofield + +# F - Flanges: F160, F100, F200 (used only when the Asymmetry check is OFF) +# F160 - 160 CF flange upstream of MCP2 tube +# F100 (Blank end flange) # OLD Value was 162.0 +/musr/command construct tubs F160 78.0 101.25 11 0 360 Steel 0 0 -151.0 log_World norot dead 901 nofield +/musr/command construct tubs F100 0 75.0 10 0 360 Steel 0 0 172.0 log_World norot dead 902 nofield + +# NOTE: Original F100 referred to MCPV (as shown below) was moved to World. +#/musr/command construct tubs F100 0 76.5 10 0 360 Steel 0 0 264.5 log_MCPV norot dead 902 nofield + + +# Experimental Area visual attributes (optional) +/musr/command visattributes log_MCPV invisible +/musr/command visattributes log_MCPS invisible +/musr/command visattributes log_F160 blue_style +/musr/command visattributes log_F100 blue_style + + + + +#=============================================================================================================== +# MCP - Micro Channel Plate Detector MCP2 (Used as an alternative to cryostat) # mcpv_z = -92.5 mm! +# +# We have a 324 mm long sample tube; +# the MCP2 front side is at 142 mm from the end of the sample tube. +# the front face of the sample plate of the cryostat is 145 mm from the end of the sample tube. +# +#=============================================================================================================== + +# MCPM1 - MCP Macor ring 1 +# MCPD - electron multiplying glass disk (also known as target) +# Sensitive surface at z = 20 mm wrt. World +# MCPM2 - MCP Macor ring 2 +#*/musr/command construct tubs MCPM1 24 32.5 0.75 0 360 Macor 0 0 105.75 log_MCPV norot dead 201 nofield +# Use it either as (DMCP-musr/ScintSD) - no info on mu+ polariz., or as (target-dead) with info on mu+ polariz. +#*/musr/command construct tubs target 0 25.0 1.50 0 360 MCPglass 0 0 108.0 log_MCPV norot dead 032 nofield +/musr/command construct tubs MCPM2 24 32.5 0.75 0 360 Macor 0 0 116.25 log_MCPV norot dead 203 nofield +# NOTE: To intercept ALL the incoming muons, comment the DMCP and MCPM1 lines above and uncomment this one: +#*/musr/command construct tubs DMCP 0 76.5 1.5 0 360 MCPglass 0 0 108 log_MCPV norot musr/ScintSD 202 nofield +/musr/command construct tubs target 0 75.0 1.5 0 360 MCPglass 0 0 114 log_MCPV norot musr/ScintSD 202 nofield + +# MCSR - Stainless Steel Ring for MCP2 mounting (modelled as a box with a circular hole) +# MCVR - "Vacuum Ring" (circular hole) +/musr/command construct box MCSR 36.5 36.5 1 Steel 0 0 118.5 log_MCPV norot dead 204 nofield +/musr/command construct tubs MCVR 0 27.5 1 0 360 G4_Galactic 0 0 0 log_MCSR norot dead 205 nofield + +# MCPA = MCP Anode (modelled as a box with two symmetrically subtracted "vacuum" disks) +# ANVA1 - Anode "Vacuum" 1 - Part of MCP Anode +# ANVA2 - Anode "Vacuum" 2 - Part of MCP Anode +/musr/command construct box MCPA 36.5 36.5 4 Steel 0 0 129.5 log_MCPV norot dead 206 nofield +/musr/command construct tubs ANVA1 0 27.5 1.5 0 360 G4_Galactic 0 0 -2.5 log_MCPA norot dead 207 nofield +/musr/command construct tubs ANVA2 0 27.5 1.5 0 360 G4_Galactic 0 0 2.5 log_MCPA norot dead 208 nofield + +# MCSS - MCP Stainless Steel Support Ring +/musr/command construct tubs MCSS 40 48 2.5 0 360 Steel 0 0 162.3 log_MCPV norot dead 209 nofield + + +# MCP2 visual attributes (optional) +#/musr/command visattributes log_DMCP MCP_style +#*/musr/command visattributes log_target MCP_style +#*/musr/command visattributes log_MCPM1 MACOR_style +/musr/command visattributes log_MCPM2 MACOR_style + + + + +#=============================================================================================================== +# CRY - Cryostat - Used as an ALTERNATIVE to MCP2 - Uncomment lines with #*. (Offset = 0.0 cm) +# +# at the moment, sample plate front face is still at z = 14.0mm --> should be changed to 17mm. +#=============================================================================================================== + +# SAH - SAmple Holder components (Cu plate) Cu or Al plates 1. Cu plate (sample holder) on Cold finger, 0.5cm +# SAPH - SAPpHire plate mounted between 1st and 2nd Cu plates, 6 mm thick, 60 mm diameter. +# SAH3 is ignored because currently NOT use. +#*/musr/command construct tubs SAH1 0 35 2.5 0 360 G4_Cu 0 0 119.0 log_MCPV norot dead 251 nofield +#*/musr/command construct tubs SAH2 0 35 2 0 360 G4_Cu 0 0 108.5 log_MCPV norot dead 252 nofield +#/musr/command construct tubs SAH3 20 35 0.5 0 360 G4_Cu 0 0 106.0 log_MCPV norot dead 253 nofield +#*/musr/command construct tubs SAPH 0 30 3 0 360 G4_ALUMINUM_OXIDE 0 0 113.5 log_MCPV norot dead 254 nofield + +# Other components of the CRYostat (dimensions and position of CRY4 are only approx. because unknown) +# COFI - COld FInger +# CRY1 - End plate of cryostat (7 mm thick, 30 mm diameter) +# CRY2 - Heat exchanger (assuming a 10 mm opening - Original dimensions not known.) # OLD pos. 160.0 +# CRY3 - Mounting ring for He-shield +# CRY4 - 2 mm thick plate for mounting ring. This is just to close the downstream side. +# CRSH - Lateral He-shield +# CRSH2- Frontal He-shield Ring +#*/musr/command construct tubs COFI 0 27.5 5 0 360 G4_Cu 0 0 126.5 log_MCPV norot dead 261 nofield +#*/musr/command construct tubs CRY1 0 15 3.5 0 360 G4_Cu 0 0 135.0 log_MCPV norot dead 262 nofield +#*/musr/command construct tubs CRY2 5 15 25 0 360 G4_Cu 0 0 163.5 log_MCPV norot dead 263 nofield +#*/musr/command construct tubs CRY3 38 47 5.5 0 360 G4_Cu 0 0 143.5 log_MCPV norot dead 264 nofield +#*/musr/command construct tubs CRY4 15 38 1 0 360 G4_Cu 0 0 143.5 log_MCPV norot dead 265 nofield +#*/musr/command construct tubs CRSH 47 48 45 0 360 G4_Cu 0 0 108.5 log_MCPV norot dead 266 nofield +#*/musr/command construct tubs CRSH2 30 48 0.5 0 360 G4_Cu 0 0 63.0 log_MCPV norot dead 267 nofield + +# Electrical Field Guard Rings (distance between the guard rings: 16 mm) +#*/musr/command construct tubs Guard1 29 38 1.5 0 360 G4_Cu 0 0 76.0 log_MCPV norot dead 271 nofield +#*/musr/command construct tubs Guard2 29 38 1.5 0 360 G4_Cu 0 0 92.0 log_MCPV norot dead 272 nofield + + +# Cryostat visual attributes (optional) +#*/musr/command visattributes log_SAH1 oxsteel +#*/musr/command visattributes log_SAH2 oxsteel +#*/musr/command visattributes log_SAPH MACOR_style +#/musr/command visattributes log_SAH3 oxsteel +#/musr/command visattributes log_CRSH invisible + + + + +#=============================================================================================================== +# RA - Ring Anode, M - middle part (closer to Ground Anode), E - end part (farther from the Ground Anode) +# U - up, D - down, L - left, R - right (with respect to muon's view - momentum direction) +# Note: 3.0 mm HALF gap at 45.1469 mm half radius => delta_ang = asin(3.0/45.1469)*180/pi = 3.81 deg. +# Note: delta_ang = 3.1744 deg. for 2.5 mm HG. The angular extension goes e.g. from (45 + da) to (90 - 2*da). +# Note: Ring Anode - Ground Anode distance was 15 mm => CHANGED to 12 mm! (Positions: 11.5 -> 8.5, -33.5 -> -36.5) +#=============================================================================================================== + +# RA_Ez = -10.35+2.25 = -8.1 cm; RA_Mz= -10.35 - 2.25 = -12.6 cm; RA_Gz= -25.45+3.75 = -21.7 cm; mcpv_z = -9.25 cm +/musr/command construct cons RA_EU 45.1469 62.5 33.5 39.0 22.5 48.81 82.38 Steel 0 0 8.5 log_MCPV norot dead 301 nofield +/musr/command construct cons RA_MU 56.7937 62.5 45.147 62.5 22.5 48.81 82.38 Steel 0 0 -36.5 log_MCPV norot dead 302 nofield +/musr/command construct cons RA_ER 45.1469 62.5 33.5 39.0 22.5 48.81 82.38 Steel 0 0 8.5 log_MCPV rotRAnR dead 303 nofield +/musr/command construct cons RA_MR 56.7937 62.5 45.147 62.5 22.5 48.81 82.38 Steel 0 0 -36.5 log_MCPV rotRAnR dead 304 nofield +/musr/command construct cons RA_ED 45.1469 62.5 33.5 39.0 22.5 48.81 82.38 Steel 0 0 8.5 log_MCPV rotRAnD dead 305 nofield +/musr/command construct cons RA_MD 56.7937 62.5 45.147 62.5 22.5 48.81 82.38 Steel 0 0 -36.5 log_MCPV rotRAnD dead 306 nofield +/musr/command construct cons RA_EL 45.1469 62.5 33.5 39.0 22.5 48.81 82.38 Steel 0 0 8.5 log_MCPV rotRAnL dead 307 nofield +/musr/command construct cons RA_ML 56.7937 62.5 45.147 62.5 22.5 48.81 82.38 Steel 0 0 -36.5 log_MCPV rotRAnL dead 308 nofield + + +# Dummy, thin cylindres used for applying the SAME RA field-map (ROTATED by 90 deg.) to different anodes. +# NOTE: EM field cannot be applied to non simply connected bodies, as e.g. rings, cones, tori, etc.! +/musr/command construct tubs RA_U 0 0.01 0.005 0 360 G4_Galactic 0 0 -50.50 log_MCPV norot dead 322 nofield +/musr/command construct tubs RA_R 0 0.01 0.005 0 360 G4_Galactic 0 0 -50.52 log_MCPV rotRAnR dead 324 nofield +/musr/command construct tubs RA_D 0 0.01 0.005 0 360 G4_Galactic 0 0 -50.54 log_MCPV rotRAnD dead 326 nofield +/musr/command construct tubs RA_L 0 0.01 0.005 0 360 G4_Galactic 0 0 -50.56 log_MCPV rotRAnL dead 328 nofield + + +# RA_G - Ring Anode Ground Cylinder +/musr/command construct tubs RA_G 58 62.5 58.0 0 360 G4_Cu 0 0 -129.0 log_MCPV norot dead 351 nofield + + +# Ring Anodes visual attributes (optional) +/musr/command visattributes log_RA_EU oxsteel +/musr/command visattributes log_RA_MR oxsteel +/musr/command visattributes log_RA_G Grid_style + + +# Alternative placement using World as a mother volume (mcpv_z = -92.5 mm). Check latter. These values refer to a 5 mm GAP! +#/musr/command construct cons RA_EU 45.1469 62.5 33.5 39.0 22.5 48.1711 83.6578 Steel 0 0 -81 log_World norot dead 301 nofield +#/musr/command construct cons RA_MU 56.7937 62.5 45.147 62.5 22.5 48.1711 83.6578 Steel 0 0 -126 log_World norot dead 302 nofield + + + + +#=============================================================================================================== +# Gate Valve Area - Hosts the Ground Anode (upstream part of the Ring Anode) - Delimited by L3F1 and F200 flanges +#=============================================================================================================== + +# GATS - 200 CF flange upstream of MCP2 tube covering the whole length of the gate valve chamber. For simplicity, we +# choose the INNER diameter of the GATe valve Steel tube the same as the OUTER diameter of F200 (200 CF flange) +/musr/command construct tubs GATS 103.25 126.5 92.5 0 360 Steel 0 0 -254.5 log_World norot dead 371 nofield + +# Vacuum "Ring" (to avoid intersections with MCPV) - Not needed if world is already filled with vacuum. +#*/musr/command construct tubs GATV 76.5 103.25 92.5 0 360 G4_Galactic 0 0 -254.5 log_World norot dead 370 nofield + +# F200 - 200 CF flange upstream of MCP2 tube to connect to gate valve chamber +/musr/command construct tubs F200 76.5 103.25 12 0 360 Steel 0 0 -174.0 log_World norot dead 372 nofield + +# NOTE: When using GATV comment the F200 above and uncomment the following (change mother to log_GATV). +#*/musr/command construct tubs F200 76.5 103.25 12 0 360 Steel 0 0 80.5 log_GATV norot dead 372 nofield + + +# Gate Valve Area visual attributes (optional) +/musr/command visattributes log_GATS SCINT_style +/musr/command visattributes log_F200 blue_style + + + + +#=============================================================================================================== +# L3 - 3rd Einzel Lens # L3z = -56.7 cm. ATT: DUMMY FIELD change to electric L3Efield! +#=============================================================================================================== +# Lens Gap = 12.0 mm => G/D = 12/130 ~ 0.1 (Lens Gap = gap between Ground and Anode, D - Diameter) + +# L3 envelope (Tube + Flanges) +# L3VA - Lens 3 Vacuum +# L3ST - Lens 3 Steel tube (inner dia: 200 mm, outer dia: 206 mm, length: 720 mm) +# L3F1 - Lens 3 Flange 1, z = L3z + 208 mm +# L3F2 - Lens 3 Flange 2, z = L3z - 208 mm + +/musr/command construct tubs L3VA 0 100 220 0 360 G4_Galactic 0 0 -567 log_World norot dead 400 nofield +/musr/command construct tubs L3ST 100 103 220 0 360 Steel 0 0 -567 log_World norot dead 401 nofield +/musr/command construct tubs L3F1 103 126.5 12 0 360 Steel 0 0 -359 log_World norot dead 402 nofield +/musr/command construct tubs L3F2 103 126.5 12 0 360 Steel 0 0 -775 log_World norot dead 403 nofield + +# GPn - Ground Potential Electrodes +# n = 1-4 and 5-8 - components of the Ground Electrodes +# GP1 - Ground Electrode (inner dia: 130 mm, outer dia: 134 mm, length: 133 mm) +# GP2 - outer electrode surface (LN2 cooling vessel) +# GP3 - first ring cap +# GP4 - second ring cap + +# n = 1-4 - Ground Electrode 1 (further from TD). See above for the meaning of acronyms. +/musr/command construct tubs L3GP1 65 67 66.5 0 360 Steel 0 0 133.5 log_L3VA norot dead 421 nofield +/musr/command construct tubs L3GP2 81 83 66.5 0 360 Steel 0 0 133.5 log_L3VA norot dead 422 nofield +/musr/command construct tubs L3GP3 67 81 4 0 360 Steel 0 0 196.0 log_L3VA norot dead 423 nofield +/musr/command construct tubs L3GP4 67 81 4 0 360 Steel 0 0 71.0 log_L3VA norot dead 424 nofield + +# n = 5-8 - Ground Electrode 2 (closer to TD). See above for the meaning of acronyms. +/musr/command construct tubs L3GP5 65 67 66.5 0 360 Steel 0 0 -133.5 log_L3VA norot dead 431 nofield +/musr/command construct tubs L3GP6 81 83 66.5 0 360 Steel 0 0 -133.5 log_L3VA norot dead 432 nofield +/musr/command construct tubs L3GP7 67 81 4 0 360 Steel 0 0 -196.0 log_L3VA norot dead 433 nofield +/musr/command construct tubs L3GP8 67 81 4 0 360 Steel 0 0 -71.0 log_L3VA norot dead 434 nofield + +# HP - High Potential Electrode (Central Anode - usually at +8.7 kV, for a 15 keV muon beam) +/musr/command construct tubs L3HP 65 83 55 0 360 Steel 0 0 0 log_L3VA norot dead 451 nofield + + +# Lens 3 visual attributes (optional) +/musr/command visattributes log_L3VA invisible +/musr/command visattributes log_L3ST invisible +/musr/command visattributes log_L3HP darkred + + + + +#=============================================================================================================== +# IP - Intermediate Piece (between Trigger Detector and Einzel Lens 3) +# Original name was CGate - B-field Coil Compensation Gate?! # CompGatez = -86.55 cm; // L3z - 22 - 7.85 cm +#=============================================================================================================== +# IPV (but also others) are just empty volumes "filled" with vacuum. Sometimes used to apply EM fields to restricted areas. +/musr/command construct tubs IPV 0 100 78.5 0 360 G4_Galactic 0 0 -865.5 log_World norot dead 500 nofield +# IPCF - Intermediate Piece Central Flange (same as L3 Flanges) +# IPST - Intermediate Piece Steel Tube (same diameter as L3 Steel Tube) +/musr/command construct tubs IPCF 103 126.5 12.0 0 360 Steel 0 0 -865.5 log_World norot dead 501 nofield +/musr/command construct tubs IPST 100 103 78.5 0 360 Steel 0 0 -865.5 log_World norot dead 502 nofield + + +# IP visual attributes (optional) +/musr/command visattributes log_IPV invisible +/musr/command visattributes log_IPCF blue_style +/musr/command visattributes log_IPST gray + + + + +#=============================================================================================================== +# Trigger - Trigger Detector # Triggerz = -1092 mm; total length of TD is 110 mm; carbon foil at -1144 mm. +#=============================================================================================================== + +# Trigger tube and relative vacuum +/musr/command construct tubs TriggerV 0 100 148 0 360 G4_Galactic 0 0 -1092 log_World norot dead 600 nofield +/musr/command construct tubs Trigger 100 103 148 0 360 Steel 0 0 -1092 log_World norot dead 601 nofield + +# TF - Trigger tube flanges +/musr/command construct tubs TF1 103 126.5 12 0 360 Steel 0 0 -956 log_World norot dead 611 nofield +/musr/command construct tubs TF2 103 126.5 12 0 360 Steel 0 0 -1228 log_World norot dead 612 nofield + +#------------------------------------------------------------- +# trigger foil is 52mm upstream of Triggerz, i.e. at -1144 mm +#------------------------------------------------------------- +# Carbon Foil (default HALF-thickness 0.000005147 mm, see below => CFoil thick = 10.3 nm). +# USE THE NAME CFoil or coulombCFoil, otherwise musrMuFormation won't work! +####/musr/command construct box CFoil 60 60 0.000005147 G4_GRAPHITE 0 0 -45 log_TriggerV norot dead 621 nofield +/musr/command construct box CFoil 60 60 0.0000049 G4_GRAPHITE 0 0 -52.1 log_TriggerV norot dead 621 nofield +####/musr/command construct box coulombCFoil 60 60 0.000005147 G4_GRAPHITE 0 0 -45 log_TriggerV norot dead 621 nofield + +# Notes: NIST tables use G4_GRAPHITE with 1.7 g/cm3 and 78 eV ioniz. energy. +# An area density of 2.20 ug/cm2 implies a CF thickn. = (2.20*1.e-6/1.70)*cm = 1.294e-5 mm - Total thickness +# An area density of 1.75 ug/cm2 implies a CF thickn. = (1.75*1.e-6/1.70)*cm = 1.029e-5 mm - Total thickness +# If necessary, use Graphite as defined in musrDetectorConstruction.cc and set any density. + +# Dummy plane to intercept outgoing muons from the Carbon foil. +#*/musr/command construct box saveCFoil 60 60 5e-4 G4_Galactic 0 0 -52.0005 log_TriggerV norot dead 623 nofield +/musr/command construct box saveAfterTD 60 60 5e-4 G4_Galactic 0 0 58.0006 log_TriggerV norot dead 623 nofield + + +# Electrical Field areas in the Trigger Detector +# En = Electrical Field n: TnFieldMgr (n = 1-3) +# Original TriggE2: [4.*sqrt(2), 4.5, 0.7/sqrt(2)] cm -> changed due to overlaps with E1 and E3 +/musr/command construct box TriggE0 45 45 5 G4_Galactic 0 0 -57.15 log_TriggerV norot dead 630 nofield +/musr/command construct box TriggE1 45 45 4 G4_Galactic 0 0 -48.0 log_TriggerV norot dead 631 nofield +/musr/command construct box TriggE2 45 45 4.9497 G4_Galactic 0 0 2.25 log_TriggerV rotTrig dead 632 nofield +/musr/command construct box TriggE3 45 45 4 G4_Galactic 0 0 54.0 log_TriggerV norot dead 633 + +# Beam spot (just for having a visual idea!) +/musr/command construct tubs BSpot 0 20 1 0 360 G4_Galactic 0 0 -63.15 log_TriggerV norot dead 650 nofield + + +# Trigger visual attributes (optional) +/musr/command visattributes log_TriggerV invisible +/musr/command visattributes log_Trigger invisible +#*/musr/command visattributes saveCFoil MACOR_style +/musr/command visattributes log_saveAfterTD darkred +/musr/command visattributes log_BSpot darkred + +# One can set visible attrib. also on a MATERIAL basis, rather than on log_VOL. +# E.g. /musr/command visattributes Steel red + + + + + +################################################################################################################ +# -- Setting the ELECTRIC and MAGNETIC fields -- +################################################################################################################ + +# Use ABSOLUTE coordinates to specify the field position (i.e. with respect to GLOBAL WORLD)! +# Default field units: Magnetic - T, Electric - kV/mm (or kV for E-field maps). +# NOTE: Applying a field to an invisible log_vol makes is visible! + +### Electric field at TRIGGER Detector TD: Three different uniform fields +/musr/command globalfield Trigg0_field 45 45 5 uniform 0. 0. -1149.15 log_TriggE0 0 0 0 0 0 0.373 +/musr/command globalfield Trigg1_field 45 45 4 uniform 0. 0. -1140. log_TriggE1 0 0 0 0 0 -0.02375 +/musr/command globalfield Trigg2_field 45 45 4.9497 uniform 0. 0. -1089.75 log_TriggE2 0 0 0 0 0 0.041416 +/musr/command globalfield Trigg3_field 45 45 4 uniform 0. 0. -1038.0 log_TriggE3 0 0 0 0 0 -0.49375 + + +### Electric field at Einzel LENS 3 - from folded 2D axial field map (f - folded, i.e. symmetric) +# Typically V = +8.7 kV for a muon beam at 15 keV. Use either 2DE L3_Erz.map or +# +# ATTENTION: The electric field is ANTI-symmetric: DO NOT use folded field map L3_Erz4.map!! +# +/musr/command globalfield Lens3_field 0. 0. -567. fromfile 2DE L3_Erz.map log_L3VA 6.51 +# To change the field in regular steps (e.g. for testing) use (f_min f_max step_no), e.g.: +#*/musr/command globalfield Lens3_field 0. 0. -567. fromfile 2DE L3_Erz.map log_L3VA 7 11 5 + + +### Electric field at RING ANODE - from 3DE field map +# Typically set at +11.0 kV for a muon beam at 15 keV +# To create an arbitrary configuration, switch on all fields and set different potentials. +#######/musr/command globalfield RngAnU_field 0. 0. -167.00 fromfile 3DE EM_3D_extc.map log_RA_U 11.0 +/musr/command globalfield RngAnU_field 0. 0. -143.00 fromfile 3DE EM_3D_ext_gridf.map log_RA_U 8.26 +/musr/command globalfield RngAnR_field 0. 0. -143.02 fromfile 3DE EM_3D_ext_gridf.map log_RA_R 8.26 +/musr/command globalfield RngAnD_field 0. 0. -143.04 fromfile 3DE EM_3D_ext_gridf.map log_RA_D 8.26 +/musr/command globalfield RngAnL_field 0. 0. -143.06 fromfile 3DE EM_3D_ext_gridf.map log_RA_L 8.26 + +### LAST FIELD OK: EM_3D_ext2f.map +# EXTENDED MAPS (from -28 to +20 mm) EM_3D_extc.map or EM_3D_extf.map (coord + field or field only) +# "Best" results with EM_RA_3D.map, even though this is not a precise map (poor meshing). +#RA_1kV_upf_raw.map +#RA_1kV_upf.map # EM_extendf2.map give rise to "strange spots" -> lem4_1047_RA13.eps + +### Electric field at SAMPLE space. Three possible field maps: Sample, G1 and G2 (closest to sample) +# To create an arbitrary configuration, switch on all fields and set different potentials. +# Field extension along z: 50 mm. Center of MCPV at z = -92.5 mm. Sample face at: z = 108.5 (4 mm thick - SAH2). +# Position of the field: (-92.5 - 50/2) + (108.5 - 4/2) = -11 mm wrt. WORLD! => +#*/musr/command globalfield Sample_field 0. 0. -11.0 fromfile 2DE sample_Erz.map log_MCPV 9.0 +#*/musr/command globalfield Guard2_field 0. 0. -11.0 fromfile 2DE guard2_Erz.map log_MCPV 6.0 +#*/musr/command globalfield Guard1_field 0. 0. -11.0 fromfile 2DE guard1_Erz.map log_MCPV 3.0 + + +### Magnetic field at SAMPLE space (use either a uniform field or a field map). +# Use either DMCP or MCPV to apply a CONSTANT field strictly to the sample or also to the surroundings, resp.! +#*/musr/command globalfield Magnet_field ? ? ? uniform 0. 0. 14.5 log_DMCP 0 0.005 0 0 0 0 +# Use field map to set field to 20 G TF +# Extended map has -100/100 cm z extension, field center at +70, original -85/85, center at +85 +#######/musr/command globalfield Magnet_field 0. 0. -836.0 fromfile 2DB sample_Brz.map log_IPV 0.002 +#*/musr/command globalfield Magnet_field 0. 0. -686.0 fromfile 2DB sample_Brz_ext.map log_L3VA 0.002 + + +# Set parameters for particle tracking in an EM field +/musr/command globalfield setparameter SetLargestAcceptableStep 5 +/musr/command globalfield setparameter SetMinimumEpsilonStep 5e-5 +/musr/command globalfield setparameter SetMaximumEpsilonStep 0.001 +/musr/command globalfield setparameter SetDeltaOneStep 0.1 +/musr/command globalfield setparameter SetDeltaIntersection 0.01 +/musr/command globalfield printparameters + + + + +################################################################################################################ +# -- Testing the ELECTRIC and MAGNETIC fields (OPTIONAL) -- +################################################################################################################ + +# FIELD CHECKS at different beam transport components (from trigg. to sample) +# All distances in mm and in GLOBAL coordinates (preferably at field center) +# The test points below are just some examples. Any point can be checked. + +# Trigger 0 +/musr/command globalfield printFieldValueAtPoint 0. 0. -1149.15 + +# Trigger 1 +/musr/command globalfield printFieldValueAtPoint 0. 0. -1140. +# Trigger 2 +/musr/command globalfield printFieldValueAtPoint 0. 0. -1089.75 +# Trigger 3 +/musr/command globalfield printFieldValueAtPoint 0. 0. -1038.0 + +# Einzel Lens 3 - L3 (center at -567.0, but max field at rel. +/-62 mm) +/musr/command globalfield printFieldValueAtPoint 0. 0. -507.0 + +# Ring Anode - RA (center at -167.0, but max field at rel. -16/+132 mm) +/musr/command globalfield printFieldValueAtPoint 0. 0. -35.0 + +# Sample space (center at -11.0, but max field at rel. +24 mm) +/musr/command globalfield printFieldValueAtPoint 0. 0. 13.0 + +# Check magnetic field at sample space +#*/musr/command globalfield printFieldValueAtPoint 10. 0. 13.0 +# Check magnetic field at the lower field end limit +#*/musr/command globalfield printFieldValueAtPoint 0. 20. -1680. + + + +################################################################################### +######################### P H Y S I C S P R O C E S S E S ################## +################################################################################### +# --- Low Energy (default) --- +/musr/command process addDiscreteProcess gamma G4LowEnergyPhotoElectric +/musr/command process addDiscreteProcess gamma G4LowEnergyCompton +/musr/command process addDiscreteProcess gamma G4LowEnergyGammaConversion +/musr/command process addDiscreteProcess gamma G4LowEnergyRayleigh +/musr/command process addProcess e- G4MultipleScattering -1 1 1 +#/musr/command process addDiscreteProcess e- G4CoulombScattering +/musr/command process addProcess e- G4LowEnergyIonisation -1 2 2 +/musr/command process addProcess e- G4LowEnergyBremsstrahlung -1 -1 3 +/musr/command process addProcess e+ G4MultipleScattering -1 1 1 +#/musr/command process addDiscreteProcess e+ G4CoulombScattering +/musr/command process addProcess e+ G4eIonisation -1 2 2 +/musr/command process addProcess e+ G4eBremsstrahlung -1 3 3 +/musr/command process addProcess e+ G4eplusAnnihilation 0 -1 4 +# +# --- High Energy --- +#/musr/command process addDiscreteProcess gamma G4PhotoElectricEffect +#/musr/command process addDiscreteProcess gamma G4ComptonScattering +#/musr/command process addDiscreteProcess gamma G4GammaConversion +#/musr/command process addProcess e- G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e- G4CoulombScattering +#/musr/command process addProcess e- G4eIonisation -1 2 2 +#/musr/command process addProcess e- G4eBremsstrahlung -1 3 3 +#/musr/command process addProcess e+ G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e+ G4CoulombScattering +#/musr/command process addProcess e+ G4eIonisation -1 2 2 +#/musr/command process addProcess e+ G4eBremsstrahlung -1 3 3 +#/musr/command process addProcess e+ G4eplusAnnihilation 0 -1 4 +# +# --- Penelope --- +#/musr/command process addDiscreteProcess gamma G4PenelopePhotoElectric +#/musr/command process addDiscreteProcess gamma G4PenelopeCompton +#/musr/command process addDiscreteProcess gamma G4PenelopeGammaConversion +#/musr/command process addDiscreteProcess gamma G4PenelopeRayleigh +#/musr/command process addProcess e- G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e- G4CoulombScattering +#/musr/command process addProcess e- G4PenelopeIonisation -1 2 2 +#/musr/command process addProcess e- G4PenelopeBremsstrahlung -1 -1 3 +#/musr/command process addProcess e+ G4MultipleScattering -1 1 1 +##/musr/command process addDiscreteProcess e+ G4CoulombScattering +#/musr/command process addProcess e+ G4PenelopeIonisation, -1 2 2 +#/musr/command process addProcess e+ G4PenelopeBremsstrahlung, -1 -1 3 +#/musr/command process addProcess e+ G4PenelopeAnnihilation, 0 -1 4 +# +# --- Muons --- +/musr/command process addProcess mu+ G4MultipleScattering -1 1 1 +#/musr/command process addProcess mu+ MultipleAndCoulombScattering -1 1 1 goulombRegion +#/musr/command process addDiscreteProcess mu+ G4CoulombScattering +/musr/command process addProcess mu+ G4MuIonisation -1 2 2 +/musr/command process addProcess mu+ G4MuBremsstrahlung -1 3 3 +/musr/command process addProcess mu+ G4MuPairProduction -1 4 4 +/musr/command process addProcess mu- G4MultipleScattering -1 1 1 +#/musr/command process addDiscreteProcess mu- G4CoulombScattering +/musr/command process addProcess mu- G4MuIonisation -1 2 2 +/musr/command process addProcess mu- G4MuBremsstrahlung -1 3 3 +/musr/command process addProcess mu- G4MuPairProduction -1 4 4 +# --- Muonium --- +/musr/command process addProcess mu+ musrMuFormation -1 -1 2 +#cks - the following line not supported yet, has to be tested (at the moment, musrMuScatter is hard wired in the musrPhysicsList.cc): +#/musr/command process addProcess Mu musrMuScatter -1 -1 1 +################################################################################################################ +# -- Setting simulation PARAMETERS -- +################################################################################################################ + +# Set the overall range cut (default 0.1 mm) +#*/run/setCut 1 mm + +# Set the range cut on particular volumes (in mm) +/musr/command SetUserLimits log_CFoil 1e-8 +#*/musr/command SetUserLimits log_target 0.01 +#*/musr/command SetUserLimits log_targetscint 0.01 +#*/musr/command SetUserLimits log_cryostatscint 0.01 + +# Set particle energy cuts on particular volumes (in MeV) +#/musr/command SetUserMinEkine log_World 0.1 +#/musr/command SetUserLimits log_World ustepMax(mm) utrakMax(mm) utimeMax(ns) uekinMin(MeV) urangMin(mm) +/musr/command SetUserLimits log_World -1 -1 -1 1e-7 -1 + +# Store ALL the events in a ROOT tree or just the interesting ones? (default is true) +#*/musr/command storeOnlyEventsWithHits false + +# Set the minimum time separation between two subsequent signals in the same detector (in ns) +/musr/command signalSeparationTime 0.1 + +# Override runID number +#*/musr/run/runID 21 + +# Set the frequency of event printing +/musr/run/howOftenToPrintEvent 1000 + +# RANDOM option choices: (specify the random number generator initialisation) +# 0 ... no initialisation (default) +# 1 ... use actual computer time to initialise now # Pseudo-random numbers +# 2 ... use event number to initialise at the beginning of each event # Reproducible numbers +# 3 ... read in the random no. initial values for each event from a file +/musr/run/randomOption 2 + +# VISUALIZATION options +# To enable or disable visualization uncomment one of these lines +# To modify visualization options edit the file vis.mac +/vis/disable +#*/control/execute vis.mac + + + + + +################################################################################################################ +# -- Setting PARTICLE GUN parameters -- +################################################################################################################ + +# Default momentum direction: 001, i.e. 0z. +# Default muon spin direction: 100, i.e. 0x. +# Default particle type: mu+ (can be changed to Mu) + +# Set particle type +#*/gun/particle Mu +/gun/particle mu+ + +# Set beam vertex +# CFoil at -1144 mm, acceleration starts at -1154.15 mm +/gun/vertex 0. 0. -1155. mm + +# A point-like uniform beam +/gun/vertexsigma -0.1 -0.1 0 mm + +# Set beam transverse spread (default GAUSSIAN spread) +# If FWHM = 10 mm ==> sigma = 10/2.354 = 4.2481 mm (last 0 is a dummy value) +# Negative sigma values => random FLAT RECTANGULAR distribution (area 2x.2y) +# Use vertexboundary with (vb < sigma_xy) to obtain a CIRCULAR beam spot +# /gun/vertexsigma 0 0 0 mm ==> Very SLOW with mag. field ON and centered beam +#*/gun/vertexsigma 42.5 42.5 0 mm +/gun/vertexsigma -20 -20 0 mm +/gun/vertexboundary 20 -1e6 1e6 mm + +# /gun/vertexboundary: rMaxAllowed, zMinAllowed, zMaxAllowed # Beam AND gating +#*/gun/vertexboundary 7 -1314.4 -1305 mm +# Without restrictions in z, but only on r: +#*/gun/vertexboundary 3 -1e6 1e6 mm + +# Set beam momentum (USE only as an ALTERNATIVE to setting energy!) +# /gun/momentum 0 0 29.79 MeV +#*/gun/momentum 0 0 1.8 MeV +# Energy loss at p = 1.2 MeV/c (E = 6.8 keV) => 1.23 +/- 0.2 keV +# Energy loss at p = 1.8 MeV/c (E = 15.3 keV) => 1.25 +/- 0.3 keV +# 1.2 MeV/c -> 6.8 keV, 1.8 MeV/c -> 15.3 keV +# muon rest mass = 105.658 MeV/c2 + +# Set muon energy before hitting TD; a constant field in front of the C-foil accelerates the muons +# to add 3.73 keV +/gun/kenergy 12.0 keV + +# Set beam momentum direction +/gun/direction 0.0 0.0 1.0 + +# Set muon spin direction +/gun/muonPolarizVector 1 0 0 + + +# Other useful test parameters: +# +# FWHM = 3% ==> sigma = 29.79*0.03/2.354 = 0.37965 MeV/c +#*/gun/momentumsmearing 0.37965 MeV +#---/gun/momentumboundary: pMinAllowed, pMaxAllowed, dummy +#*/gun/momentumboundary 20 40 0 MeV +#---/gun/tilt: xangle, yangle, dummy +#*/gun/tilt 0 0.5 0 deg +#---/gun/tiltsigma: xangleSigma, yangleSigma, dummy (1 degree at 1 m => 17 mm) +#*/gun/tiltsigma 0.2 0.2 0 deg +#*/gun/pitch 0.5 deg +#---/gun/decaytimelimits: decayMin, decayMax, decayTime +#*/gun/decaytimelimits 10400 10420 2197.03 ns + +# Selectively inactivate or activate sensitive detectors +#*/hits/inactivate /musr/ScintSD + +# Only for code debugging! +#/tracking/verbose 1 + +# BEAM ON +#*/run/beamOn 1000000 +#*/run/beamOn 2 +/run/beamOn 1000 + diff --git a/src/F04ElementField.cc b/src/F04ElementField.cc new file mode 100644 index 0000000..db36c87 --- /dev/null +++ b/src/F04ElementField.cc @@ -0,0 +1,200 @@ +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// + +#include "G4GeometryManager.hh" +#include "F04ElementField.hh" +#include "F04GlobalField.hh" +#include "musrParameters.hh" +#include "musrErrorMessage.hh" + +G4Navigator* F04ElementField::aNavigator; + +F04ElementField::F04ElementField(G4ThreeVector c, G4LogicalVolume* lv) +{ + elementFieldName="NAME_NOT_DEFINED"; + center = c; + + minX = minY = minZ = -DBL_MAX; + maxX = maxY = maxZ = DBL_MAX; + + // G4cout<<"Kamil: F04GlobalField: addElementField() will be called: "<addElementField(this); + + color = "1,1,1"; + + userLimits = new G4UserLimits(); + + lvolume = lv; + lvolume->SetVisAttributes(getVisAttribute(color)); + + maxStep = 1*mm; + + userLimits->SetMaxAllowedStep(maxStep); + + userLimits->SetUserMaxTrackLength(500.*m); + userLimits->SetUserMaxTime(10*ms); +// userLimits->SetUserMinEkine(0.1*MeV); +// userLimits->SetUserMinRange(1*mm); + + lvolume->SetUserLimits(userLimits); +} + +void F04ElementField::construct() +{ + G4Navigator* theNavigator = + G4TransportationManager::GetTransportationManager()-> + GetNavigatorForTracking(); + + if (!aNavigator) { + aNavigator = new G4Navigator(); + if ( theNavigator->GetWorldVolume() ) + aNavigator->SetWorldVolume(theNavigator->GetWorldVolume()); + } + + G4GeometryManager* geomManager = G4GeometryManager::GetInstance(); + + if (!geomManager->IsGeometryClosed()) { + geomManager->OpenGeometry(); + geomManager->CloseGeometry(true); + } + + G4cout<<"F04ElementField: center="<LocateGlobalPointAndSetup(center,0,false); + + G4TouchableHistoryHandle fTouchable = aNavigator-> + CreateTouchableHistoryHandle(); + + G4int depth = fTouchable->GetHistoryDepth(); + for (G4int i = 0; iGetVolume()->GetLogicalVolume() == lvolume)break; + fTouchable->MoveUpHistory(); + } + // Check that the point of origin of the field matches with the logical volume, to which it is assigned: + G4String volumeName=lvolume->GetName(); + if (fTouchable->GetVolume()->GetLogicalVolume() != lvolume) { + char eMessage[200]; + sprintf(eMessage,"F04ElementField.cc::construct(): Centre (point of origin) of the field outside the assigned logical volume \"%s\".", + volumeName.c_str()); + musrErrorMessage::GetInstance()->musrError(FATAL,eMessage,false); + } + + // G4cout<<"+!+!+! global2local VOLUME NAME: "<GetVolume()->GetName()<GetHistory()->GetTopTransform(); + + // Print out the point of the origin of the field in the local coordinate system of the logical volume: + G4ThreeVector local_center = global2local.TransformPoint(center); + G4cout<<"\t==> "< "< 0 && + (isdigit(color.c_str()[0]) || color.c_str()[0] == '.')) { + G4double red=0.0, green=0.0, blue=0.0; + if (sscanf(color.c_str(),"%lf,%lf,%lf",&red,&green,&blue) == 3) { + p = new G4VisAttributes(true,G4Color(red,green,blue)); + } else { + G4cout << " Invalid color " << color << G4endl; + } + } + + if (!p) p = new G4VisAttributes(G4VisAttributes::Invisible); + p->SetDaughtersInvisible(false); + + return p; +} + + +void F04ElementField::SetEventNrDependentField(G4double initialField, G4double finalField, G4int nrOfSteps) { + G4double eventNrStep = float(musrParameters::nrOfEventsToBeGenerated)/(nrOfSteps); + G4double fieldStep = (finalField-initialField)/(nrOfSteps-1); + // G4cout<<"musrParameters::nrOfEventsToBeGenerated="<::iterator it; + for ( it=changeFieldInStepsMap.begin() ; it != changeFieldInStepsMap.end(); it++ ) { + G4cout << "Field will be changed at event "<< (*it).first << " to the value of " << (*it).second/tesla<<" T" << G4endl; + // G4double nominalFieldValue=it->second; + // it->SetNominalFieldValue(nominalFieldValue); + } +} + + +void F04ElementField::SetElementFieldValueIfNeeded(G4int eventNr) { + std::map::iterator itr; + itr = changeFieldInStepsMap.find(eventNr); + if (itr==F04ElementField::changeFieldInStepsMap.end()) { + // eventNr was not found in the map ==> field is not going to change at this eventNr + } + else { + G4double newFieldValue = itr->second; + SetNominalFieldValue(newFieldValue); + // G4cout<<"Nominal Field changed for "<SetGuidance(" Field tracking control "); + + fStepperCMD = new G4UIcmdWithAnInteger("/field/setStepperType",this); + fStepperCMD->SetGuidance("Select stepper type for field"); + fStepperCMD->SetParameterName("choice",true); + fStepperCMD->SetDefaultValue(4); + fStepperCMD->AvailableForStates(G4State_PreInit,G4State_Idle); + + fUpdateCMD = new G4UIcmdWithoutParameter("/field/update",this); + fUpdateCMD->SetGuidance("Update Field"); + fUpdateCMD->SetGuidance("This command MUST be applied before \"beamOn\" "); + fUpdateCMD->SetGuidance("if you changed field settings."); + fUpdateCMD->AvailableForStates(G4State_PreInit,G4State_Idle); + + fMinStepCMD = new G4UIcmdWithADoubleAndUnit("/field/setMinStep",this); + fMinStepCMD->SetGuidance("Define minimal step"); + fMinStepCMD->SetParameterName("min step",false,false); + fMinStepCMD->SetDefaultUnit("mm"); + fMinStepCMD->AvailableForStates(G4State_PreInit,G4State_Idle); + + fDeltaChordCMD = new G4UIcmdWithADoubleAndUnit("/field/setDeltaChord",this); + fDeltaChordCMD->SetGuidance("Define delta chord"); + fDeltaChordCMD->SetParameterName("delta chord",false,false); + fDeltaChordCMD->SetDefaultUnit("mm"); + fDeltaChordCMD->AvailableForStates(G4State_PreInit,G4State_Idle); + + fDeltaOneStepCMD = + new G4UIcmdWithADoubleAndUnit("/field/setDeltaOneStep",this); + fDeltaOneStepCMD->SetGuidance("Define delta one step"); + fDeltaOneStepCMD->SetParameterName("delta one step",false,false); + fDeltaOneStepCMD->SetDefaultUnit("mm"); + fDeltaOneStepCMD->AvailableForStates(G4State_PreInit,G4State_Idle); + + fDeltaIntersectionCMD = + new G4UIcmdWithADoubleAndUnit("/field/setDeltaIntersection",this); + fDeltaIntersectionCMD->SetGuidance("Define delta intersection"); + fDeltaIntersectionCMD->SetParameterName("delta intersection",false,false); + fDeltaIntersectionCMD->SetDefaultUnit("mm"); + fDeltaIntersectionCMD->AvailableForStates(G4State_PreInit,G4State_Idle); + + fEpsMinCMD = new G4UIcmdWithADoubleAndUnit("/field/setEpsMin",this); + fEpsMinCMD->SetGuidance("Define eps min"); + fEpsMinCMD->SetParameterName("eps min",false,false); + fEpsMinCMD->SetDefaultUnit("mm"); + fEpsMinCMD->AvailableForStates(G4State_PreInit,G4State_Idle); + + fEpsMaxCMD = new G4UIcmdWithADoubleAndUnit("/field/setEpsMax",this); + fEpsMaxCMD->SetGuidance("Define eps max"); + fEpsMaxCMD->SetParameterName("eps max",false,false); + fEpsMaxCMD->SetDefaultUnit("mm"); + fEpsMaxCMD->AvailableForStates(G4State_PreInit,G4State_Idle); +} + +F04FieldMessenger::~F04FieldMessenger() +{ + delete detDir; + + delete fStepperCMD; + delete fMinStepCMD; + delete fDeltaChordCMD; + delete fDeltaOneStepCMD; + delete fDeltaIntersectionCMD; + delete fEpsMinCMD; + delete fEpsMaxCMD; + delete fUpdateCMD; +} + +void F04FieldMessenger::SetNewValue( G4UIcommand* command, G4String newValue) +{ + if( command == fStepperCMD ) + { + fGlobalField->SetStepperType(fStepperCMD->GetNewIntValue(newValue)); + } + if( command == fUpdateCMD ) + { + fGlobalField->updateField(); + } + if( command == fMinStepCMD ) + { + fGlobalField->SetMinStep(fMinStepCMD->GetNewDoubleValue(newValue)); + } + if( command == fDeltaChordCMD ) + { + fGlobalField->SetDeltaChord(fDeltaChordCMD->GetNewDoubleValue(newValue)); + } + if( command == fDeltaOneStepCMD ) + { + fGlobalField-> + SetDeltaOneStep(fDeltaOneStepCMD->GetNewDoubleValue(newValue)); + } + if( command == fDeltaIntersectionCMD ) + { + fGlobalField-> + SetDeltaIntersection(fDeltaIntersectionCMD->GetNewDoubleValue(newValue)); + } + if( command == fEpsMinCMD ) + { + fGlobalField->SetEpsMin(fEpsMinCMD->GetNewDoubleValue(newValue)); + } + if( command == fEpsMaxCMD ) + { + fGlobalField->SetEpsMax(fEpsMaxCMD->GetNewDoubleValue(newValue)); + } +} diff --git a/src/F04GlobalField.cc b/src/F04GlobalField.cc new file mode 100644 index 0000000..175c35c --- /dev/null +++ b/src/F04GlobalField.cc @@ -0,0 +1,330 @@ +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// + +#include + +#include "Randomize.hh" +#include "G4TransportationManager.hh" + +#include "G4ExplicitEuler.hh" +#include "G4ImplicitEuler.hh" +#include "G4SimpleRunge.hh" +#include "G4SimpleHeum.hh" +#include "G4ClassicalRK4.hh" +#include "G4CashKarpRKF45.hh" + +#include "F04GlobalField.hh" +// #include "F04GlobalFieldOldPoints.hh" //cks F04GlobalFieldOldPoints were introduced in order to keep the last few +// values of the field, so that they do not have to be recalculated, if the +// field at recent point is requested. It turned out not to be useful +// (i.e. it did not speed-up the simulation) +#include "musrRootOutput.hh" + +F04GlobalField* F04GlobalField::object = 0; + +F04GlobalField::F04GlobalField() : G4ElectroMagneticField(), + minStep(0.01*mm), deltaChord(3.0*mm), + deltaOneStep(0.01*mm), deltaIntersection(0.1*mm), + epsMin(2.5e-7*mm), epsMax(0.05*mm), + fEquation(0), fFieldManager(0), + fFieldPropagator(0), fStepper(0), fChordFinder(0) +// F04GlobalField::F04GlobalField() : G4MagneticField(), +// minStep(0.01*mm), deltaChord(3.0*mm), +// deltaOneStep(0.01*mm), deltaIntersection(0.1*mm), +// epsMin(2.5e-7*mm), epsMax(0.05*mm), +// fEquation(0), fFieldManager(0), +// fFieldPropagator(0), fStepper(0), fChordFinder(0) +{ + + fFieldMessenger = new F04FieldMessenger(this); + + fields = new FieldList(); + + fStepperType = 4 ; // ClassicalRK4 is default stepper + + // set object + + object = this; + + updateField(); + + //cks myOldFieldPoints = F04GlobalFieldOldPoints(); + +} + +F04GlobalField::~F04GlobalField() +{ + // cks 2009_05_14 + // For some reason, the "clear()" on the next line was causing the crash in some cases + // (probably when more "Elementary fields" were created). The problem appeared + // when running the 1050.mac file for the lem4. Fixed by commenting out the clear(): + // clear(); + delete fFieldMessenger; + if (fEquation) delete fEquation; + // if (fFieldManager) delete fFieldManager; + // if (fFieldPropagator) delete fFieldPropagator; + if (fStepper) delete fStepper; + if (fChordFinder) delete fChordFinder; +} + +void F04GlobalField::updateField() +{ + first = true; + + nfp = 0; + fp = 0; + + clear(); + + // Construct equ. of motion of particles through B fields + // fEquation = new G4Mag_EqRhs(this); + // Construct equ. of motion of particles through e.m. fields + // fEquation = new G4EqMagElectricField(this); + // Construct equ. of motion of particles including spin through B fields + // fEquation = new G4Mag_SpinEqRhs(this); + // Construct equ. of motion of particles including spin through e.m. fields + fEquation = new G4EqEMFieldWithSpin(this); + + // Get transportation, field, and propagator managers + G4TransportationManager* fTransportManager = + G4TransportationManager::GetTransportationManager(); + + fFieldManager = GetGlobalFieldManager(); + + fFieldPropagator = fTransportManager->GetPropagatorInField(); + + // Need to SetFieldChangesEnergy to account for a time varying electric + // field (r.f. fields) + fFieldManager->SetFieldChangesEnergy(true); + + // Set the field + fFieldManager->SetDetectorField(this); + + // Choose a stepper for integration of the equation of motion + SetStepper(); + + // Create a cord finder providing the (global field, min step length, + // a pointer to the stepper) + fChordFinder = new G4ChordFinder((G4MagneticField*)this,minStep,fStepper); + + // Set accuracy parameters + fChordFinder->SetDeltaChord( deltaChord ); + + fFieldManager->SetAccuraciesWithDeltaOneStep(deltaOneStep); + + fFieldManager->SetDeltaIntersection(deltaIntersection); + + fFieldPropagator->SetMinimumEpsilonStep(epsMin); + fFieldPropagator->SetMaximumEpsilonStep(epsMax); + + // G4cout << "Accuracy Parameters:" << + // " MinStep=" << minStep << + // " DeltaChord=" << deltaChord << + // " DeltaOneStep=" << deltaOneStep << G4endl; + // G4cout << " " << + // " DeltaIntersection=" << deltaIntersection << + // " EpsMin=" << epsMin << + // " EpsMax=" << epsMax << G4endl; + + fFieldManager->SetChordFinder(fChordFinder); + +} + +F04GlobalField* F04GlobalField::getObject() +{ + if (!object) new F04GlobalField(); + return object; +} + +void F04GlobalField::SetStepper() +{ + if(fStepper) delete fStepper; + + switch ( fStepperType ) + { + case 0: +// fStepper = new G4ExplicitEuler( fEquation, 8 ); // no spin tracking + fStepper = new G4ExplicitEuler( fEquation, 12 ); // with spin tracking + G4cout << "G4ExplicitEuler is called" << G4endl; + break; + case 1: +// fStepper = new G4ImplicitEuler( fEquation, 8 ); // no spin tracking + fStepper = new G4ImplicitEuler( fEquation, 12 ); // with spin tracking + G4cout << "G4ImplicitEuler is called" << G4endl; + break; + case 2: +// fStepper = new G4SimpleRunge( fEquation, 8 ); // no spin tracking + fStepper = new G4SimpleRunge( fEquation, 12 ); // with spin tracking + G4cout << "G4SimpleRunge is called" << G4endl; + break; + case 3: +// fStepper = new G4SimpleHeum( fEquation, 8 ); // no spin tracking + fStepper = new G4SimpleHeum( fEquation, 12 ); // with spin tracking + G4cout << "G4SimpleHeum is called" << G4endl; + break; + case 4: +// fStepper = new G4ClassicalRK4( fEquation, 8 ); // no spin tracking + fStepper = new G4ClassicalRK4( fEquation, 12 ); // with spin tracking + G4cout << "G4ClassicalRK4 (default) is called" << G4endl; + break; + case 5: +// fStepper = new G4CashKarpRKF45( fEquation, 8 ); // no spin tracking + fStepper = new G4CashKarpRKF45( fEquation, 12 ); // with spin tracking + G4cout << "G4CashKarpRKF45 is called" << G4endl; + break; + default: fStepper = 0; + } +} + +G4FieldManager* F04GlobalField::GetGlobalFieldManager() +{ + return G4TransportationManager::GetTransportationManager() + ->GetFieldManager(); +} + +void F04GlobalField::GetFieldValue(const G4double* point, G4double* field) const +{ + // NOTE: this routine dominates the CPU time for tracking. + // Using the simple array fp[] instead of fields[] + // directly sped it up + + // G4cout<<"GlobalField: Field requested at point ("<setupArray(); // (cast away const) + + for (int i=0; iisInBoundingBox(point)) { + p->addFieldValue(point,field); + } + } + + // cks NOT SURE WHETHER THE FOLLOWING WAS STILL NEEDED, HOWEVER REMOVED NOT + // TO DISTURB THE LOW ENERGY MUONS. + // Set some small field if field is almost zero (to avoid internal problems + // of Geant at almost zero magnetic fields). + // if (sqrt(field[0]*field[0]+field[1]*field[1]+field[2]*field[2])<0.00001*tesla) { + // field[2] = 0.00001*tesla; + // } + + // cks myOldFieldPoints.StoreTheFieldPointForFutureReuse(point,field); +} + +void F04GlobalField::clear() +{ + if (fields) { + if (fields->size()>0) { + FieldList::iterator i; + //cks 2009_05_14 : The following line seems to cause problems (sometimes) + // See the comment in F04GlobalField::~F04GlobalField() for more details. + for (i=fields->begin(); i!=fields->end(); ++i) delete *i; + fields->clear(); + } + } + + if (fp) delete[] fp; + first = true; + + nfp = 0; + fp = NULL; +} + +void F04GlobalField::setupArray() +{ + first = false; + nfp = fields->size(); + fp = new const F04ElementField* [nfp+1]; // add 1 so it's never 0 + for (int i=0; i localChangeFieldInStepsMap = fp[i] ->GetEventNrDependentField(); + std::map::iterator it; + for ( it=localChangeFieldInStepsMap.begin() ; it != localChangeFieldInStepsMap.end(); it++ ) { + G4int eventNr = it->first; + G4cout<<"globalChangeFieldInStepsMap set for event number "<SetNrFieldNomVal(nfp); +} + + +void F04GlobalField::CheckWhetherAnyNominalFieldValueNeedsToBeChanged(G4int eventNumber) { + if (globalChangeFieldInStepsMap[eventNumber]) { + // G4cout<<"We should check each Element Field Object whether its field needs to be changed:"<begin(); i!=fields->end(); ++i) { + + // Set the nominal field value for the given field, if that has been requested for the given field + (*i)->SetElementFieldValueIfNeeded(eventNumber); + + // Get the nominal field value for the given field and store it in the Root output + G4double nomFieldValue = (*i)->GetNominalFieldValue(); + musrRootOutput::GetRootInstance()->SetFieldNomVal(jjj,nomFieldValue); + jjj++; + } + } +} + + + +// Print field value at all points requested by the user: +void F04GlobalField::PrintFieldAtRequestedPoints() const { + G4ThreeVector p; + G4double point[4]; + G4double Bfi[6]={0,0,0,0,0,0}; + for (unsigned int i=0; i < pointsAtWhichUserWantsToPrintFieldValue.size(); i++) { + p = pointsAtWhichUserWantsToPrintFieldValue[i]; + point[0] = p.x(); + point[1] = p.y(); + point[2] = p.z(); + point[3] = 0.; + object->GetFieldValue(point,Bfi); + // printf (" Magnetic Field at %f, %f, %f mm is B= %10.10f, %10.10f, %10.10f tesla.\n", + // point[0]/mm,point[1]/mm,point[2]/mm,Bfi[0]/tesla,Bfi[1]/tesla,Bfi[2]/tesla); + printf (" EM field value at (%.f, %.f, %.f) mm is: B = (%0.10g, %0.10g, %0.10g) T, E = (%0.10g, %0.10g, %0.10g) kV/mm\n", + point[0]/mm, point[1]/mm, point[2]/mm, + Bfi[0]/tesla, Bfi[1]/tesla, Bfi[2]/tesla, + Bfi[3]/(kilovolt/mm), Bfi[4]/(kilovolt/mm), Bfi[5]/(kilovolt/mm)); + } +} + + diff --git a/src/G4DecayWithSpin.cc b/src/G4DecayWithSpin.cc new file mode 100644 index 0000000..eb533a7 --- /dev/null +++ b/src/G4DecayWithSpin.cc @@ -0,0 +1,220 @@ +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// ------------------------------------------------------------ +// GEANT 4 class header file +// +// History: +// 17 August 2004 P. Gumplinger, T. MacPhail +// ------------------------------------------------------------ +// +#include "G4DecayWithSpin.hh" + +#include "G4Step.hh" +#include "G4Track.hh" +#include "G4DecayTable.hh" +#include "G4MuonDecayChannelWithSpin.hh" + +#include "G4Vector3D.hh" + +#include "G4TransportationManager.hh" +#include "G4PropagatorInField.hh" +#include "G4FieldManager.hh" +#include "G4Field.hh" + +#include "G4Transform3D.hh" + +//cks +#include "musrErrorMessage.hh" +#include "G4RunManager.hh" +//#include "musrRootOutput.hh" +//csk + +G4DecayWithSpin::G4DecayWithSpin(const G4String& processName):G4Decay(processName){} +//cks G4DecayWithSpin::G4DecayWithSpin(const G4String& processName):G4Decay(processName){SetVerboseLevel(3);} + +G4DecayWithSpin::~G4DecayWithSpin(){} + +G4VParticleChange* G4DecayWithSpin::DecayIt(const G4Track& aTrack, const G4Step& aStep) +{ + // debugging: G4RunManager* fRunManager = G4RunManager::GetRunManager(); + // debugging: G4int eventNr=fRunManager->GetCurrentEvent()->GetEventID(); + // debugging: if ((eventNr>447715)&&(eventNr<45005)) SetVerboseLevel(3); + // debugging: if (eventNr>=45005) SetVerboseLevel(0); + +// get particle + const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle(); + G4ParticleDefinition* aParticleDef = aParticle->GetDefinition(); + +// get parent_polarization + G4ThreeVector parent_polarization = aParticle->GetPolarization(); + + if(parent_polarization == G4ThreeVector(0,0,0)) + { + // Generate random polarization direction + + G4double cost = 1. - 2.*G4UniformRand(); + G4double sint = std::sqrt((1.-cost)*(1.+cost)); + + G4double phi = twopi*G4UniformRand(); + G4double sinp = std::sin(phi); + G4double cosp = std::cos(phi); + + G4double px = sint*cosp; + G4double py = sint*sinp; + G4double pz = cost; + + parent_polarization.setX(px); + parent_polarization.setY(py); + parent_polarization.setZ(pz); + + }else{ + + G4FieldManager* fieldMgr = aStep.GetTrack()->GetVolume()-> + GetLogicalVolume()->GetFieldManager(); + + if (!fieldMgr) { + G4TransportationManager *transportMgr = + G4TransportationManager::GetTransportationManager(); + G4PropagatorInField* fFieldPropagator = + transportMgr->GetPropagatorInField(); + if (fFieldPropagator) fieldMgr = + fFieldPropagator->GetCurrentFieldManager(); + } + + const G4Field* field = NULL; + if(fieldMgr)field = fieldMgr->GetDetectorField(); + + // if (field && !(fieldMgr->DoesFieldChangeEnergy())) { + if (field) { + G4double point[4]; + point[0] = (aStep.GetPostStepPoint()->GetPosition())[0]; + point[1] = (aStep.GetPostStepPoint()->GetPosition())[1]; + point[2] = (aStep.GetPostStepPoint()->GetPosition())[2]; + point[3] = aTrack.GetGlobalTime(); + + G4double fieldValue[6]; + field -> GetFieldValue(point,fieldValue); + + G4ThreeVector B(fieldValue[0],fieldValue[1],fieldValue[2]); + + if ((B.mag2())>0) { // Call the spin precession only for non-zero mag. field + parent_polarization = Spin_Precession(aStep,B,fRemainderLifeTime); + // G4cout<<"G4DecayWithSpin: parent_polarization="<1.1)||(newSpinMagnitude<0.9)) { + G4RunManager* fRunManager = G4RunManager::GetRunManager(); + G4int eventNr=fRunManager->GetCurrentEvent()->GetEventID(); + musrErrorMessage::GetInstance()->musrError(SERIOUS, + "G4DecayWithSpin.cc::Spin_Precession: NEW spin magnitude is large than 1.1 or smaller than 0.9! Strange!!!",true); + G4cout<<"G4DecayWithSpin.cc::Spin_Precession: " + <<"Event nr.:"<2) { + G4double normspin = std::sqrt(Spin*Spin); + G4double normnewspin = std::sqrt(newSpin*newSpin); + //G4double cosalpha = Spin*newSpin/normspin/normnewspin; + //G4double alpha = std::acos(cosalpha); + + G4cout << "AT REST::: PARAMETERS " << G4endl; + G4cout << "Initial spin : " << Spin << G4endl; + G4cout << "Delta time : " << deltatime << G4endl; + G4cout << "Rotation angle: " << rotationangle/rad << G4endl; + G4cout << "New spin : " << newSpin << G4endl; + G4cout << "Checked norms : " << normspin <<" " << normnewspin << G4endl; + } +#endif + + return newSpin; + +} diff --git a/src/G4EqEMFieldWithSpin.cc b/src/G4EqEMFieldWithSpin.cc new file mode 100644 index 0000000..e5b19b6 --- /dev/null +++ b/src/G4EqEMFieldWithSpin.cc @@ -0,0 +1,177 @@ +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// $Id: G4EqEMFieldWithSpin.cc,v 1.1 2008/10/21 14:50:32 sedlak Exp $ +// GEANT4 tag $Name: $ +// +// +// This is the standard right-hand side for equation of motion. +// +// The only case another is required is when using a moving reference +// frame ... or extending the class to include additional Forces, +// eg an electric field +// +// 30.08.2007 Chris Gong, Peter Gumplinger +// +// ------------------------------------------------------------------- + +#include "G4EqEMFieldWithSpin.hh" +#include "G4ThreeVector.hh" +#include "globals.hh" +//cks +#include "musrErrorMessage.hh" +#include "G4RunManager.hh" +#include "musrRootOutput.hh" +//csk + +G4EqEMFieldWithSpin::G4EqEMFieldWithSpin(G4ElectroMagneticField *emField ) + : G4EquationOfMotion( emField ) { anomaly = 1.165923e-3; } + +void +G4EqEMFieldWithSpin::SetChargeMomentumMass(G4double particleCharge, // e+ units + G4double MomentumXc, + G4double particleMass) +{ + fElectroMagCof = eplus*particleCharge*c_light ; + fMassCof = particleMass*particleMass ; + + omegac = 0.105658387*GeV/particleMass * 2.837374841e-3*(rad/cm/kilogauss); + + ParticleCharge = particleCharge; + + E = std::sqrt(sqr(MomentumXc)+sqr(particleMass)); + beta = MomentumXc/E; + gamma = E/particleMass; +} + + + +void +G4EqEMFieldWithSpin::EvaluateRhsGivenB(const G4double y[], + const G4double Field[], + G4double dydx[] ) const +{ + + // Components of y: + // 0-2 dr/ds, + // 3-5 dp/ds - momentum derivatives + + G4double pSquared = y[3]*y[3] + y[4]*y[4] + y[5]*y[5] ; + + G4double Energy = std::sqrt( pSquared + fMassCof ); + G4double cof2 = Energy/c_light ; + + G4double pModuleInverse = 1.0/std::sqrt(pSquared) ; + + // G4double inverse_velocity = Energy * c_light * pModuleInverse; + G4double inverse_velocity = Energy * pModuleInverse / c_light; + + G4double cof1 = fElectroMagCof*pModuleInverse ; + + // G4double vDotE = y[3]*Field[3] + y[4]*Field[4] + y[5]*Field[5] ; + + + dydx[0] = y[3]*pModuleInverse ; + dydx[1] = y[4]*pModuleInverse ; + dydx[2] = y[5]*pModuleInverse ; + + dydx[3] = cof1*(cof2*Field[3] + (y[4]*Field[2] - y[5]*Field[1])) ; + + dydx[4] = cof1*(cof2*Field[4] + (y[5]*Field[0] - y[3]*Field[2])) ; + + dydx[5] = cof1*(cof2*Field[5] + (y[3]*Field[1] - y[4]*Field[0])) ; + + dydx[6] = dydx[8] = 0.;//not used + + // Lab Time of flight + dydx[7] = inverse_velocity; + + G4ThreeVector BField(Field[0],Field[1],Field[2]); + + G4ThreeVector u(y[3], y[4], y[5]); + u *= pModuleInverse; + + G4double udb = anomaly*beta*gamma/(1.+gamma) * (BField * u); + G4double ucb = (anomaly+1./gamma)/beta; + + G4ThreeVector Spin(y[9],y[10],y[11]); + G4ThreeVector dSpin; + + dSpin = ParticleCharge*omegac*(ucb*(Spin.cross(BField))-udb*(Spin.cross(u))); + + // cks 2008.10.08 + // Check that Spin is not extremely high. The problem is, that in some events + // (for extremely low moementum muons?) the MomentumXc is of the order of 1.e-07, + // the ucb is extremely high (e.g. ucb = 690618107.) and then dSpin becomes + // also extremely high. This problem cummulates and results in an unreasonably + // high spin. For some reason Geant then ends up in an infinite loop. + // + // G4double spinMagnitude = Spin.mag(); + // if (spinMagnitude>1.01) dSpin /= spinMagnitude; +// if (spinMagnitude>10.) { +// dSpin=G4ThreeVector(0.,0.,0.); +// G4RunManager* fRunManager = G4RunManager::GetRunManager(); +// G4int eventNr=fRunManager->GetCurrentEvent()->GetEventID(); +// if (eventNr!=musrRootOutput::oldEventNumberInG4EqEMFieldWithSpinFunction) { +// musrRootOutput::oldEventNumberInG4EqEMFieldWithSpinFunction = eventNr; +// musrErrorMessage::GetInstance()->musrError(SERIOUS, +// "G4EqEMFieldWithSpin.cc:EvaluateRhsGivenB: spin is large than 10.! Strange!!! -> Deleting this event",true); +// G4cout<<" + G4EqEMFieldWithSpin.cc:EvaluateRhsGivenB: " +// <<"Event nr.:"<SetEventWeight(0); +// fRunManager->AbortEvent(); +// } +// } + +// if ((spinMagnitude<0.99)&&(spinMagnitude>0.1)&&( fabs(sqrt(fMassCof)/MeV-105.6584)<1) ) dSpin /= spinMagnitude; +// if ((spinMagnitude<0.2)&&( fabs(sqrt(fMassCof)/MeV-105.6584)<1) ) { +// dSpin=G4ThreeVector(0.,0.,0.); +// G4RunManager* fRunManager = G4RunManager::GetRunManager(); +// G4int eventNr=fRunManager->GetCurrentEvent()->GetEventID(); +// if (eventNr!=musrRootOutput::oldEventNumberInG4EqEMFieldWithSpinFunction) { +// musrRootOutput::oldEventNumberInG4EqEMFieldWithSpinFunction = eventNr; +// musrErrorMessage::GetInstance()->musrError(SERIOUS, +// "G4EqEMFieldWithSpin.cc:EvaluateRhsGivenB: spin for muon is smaller than 0.2! Strange!!! -> Deleting this event",true); +// G4cout<<" - G4EqEMFieldWithSpin.cc:EvaluateRhsGivenB: " +// <<"Event nr.:"<SetEventWeight(0); +// fRunManager->AbortEvent(); +// } +// } + + // + // csk + + dydx[ 9] = dSpin.x(); + dydx[10] = dSpin.y(); + dydx[11] = dSpin.z(); + + return ; +} diff --git a/src/MuDecayChannel.cc b/src/MuDecayChannel.cc new file mode 100644 index 0000000..75c500d --- /dev/null +++ b/src/MuDecayChannel.cc @@ -0,0 +1,202 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// $Id: MuDecayChannel.cc,v 1.17 2006/06/29 19:25:34 gunter Exp $ +// GEANT4 tag $Name: geant4-09-00 $ +// +// +// ------------------------------------------------------------ +// GEANT 4 class header file +// +// History: first implementation, based on object model of +// 30 May 1997 H.Kurashige +// +// Fix bug in calcuration of electron energy in DecayIt 28 Feb. 01 H.Kurashige +//2005 +// M. Melissas ( melissas AT cppm.in2p3.fr) +// J. Brunner ( brunner AT cppm.in2p3.fr) +// Adding V-A fluxes for neutrinos using a new algortithm : +// ------------------------------------------------------------ + +#include "G4ParticleDefinition.hh" +#include "G4DecayProducts.hh" +#include "G4VDecayChannel.hh" +#include "MuDecayChannel.hh" +#include "Randomize.hh" +#include "G4LorentzVector.hh" +#include "G4LorentzRotation.hh" +#include "G4RotationMatrix.hh" + +MuDecayChannel::MuDecayChannel(const G4String& theParentName, + G4double theBR) + :G4VDecayChannel("Muonium Decay",1) +{ + // set names for daughter particles + if (theParentName == "Mu") { + SetBR(theBR); + SetParent("Mu"); + SetNumberOfDaughters(3); + SetDaughter(0, "e+"); + SetDaughter(1, "nu_e"); + SetDaughter(2, "anti_nu_mu"); + } else { +#ifdef G4VERBOSE + if (GetVerboseLevel()>0) { + G4cout << "MuDecayChannel:: constructor :"; + G4cout << " parent particle is not muon but "; + G4cout << theParentName << G4endl; + } +#endif + } +} + +MuDecayChannel::~MuDecayChannel() +{ +} + +G4DecayProducts *MuDecayChannel::DecayIt(G4double) +{ + // this version neglects muon polarization,and electron mass + // assumes the pure V-A coupling + // the Neutrinos are correctly V-A. +#ifdef G4VERBOSE + if (GetVerboseLevel()>1) G4cout << "MuDecayChannel::DecayIt "; +#endif + + if (parent == 0) FillParent(); + if (daughters == 0) FillDaughters(); + + // parent mass + G4double parentmass = parent->GetPDGMass(); + + //daughters'mass + G4double daughtermass[3]; + G4double sumofdaughtermass = 0.0; + for (G4int index=0; index<3; index++){ + daughtermass[index] = daughters[index]->GetPDGMass(); + sumofdaughtermass += daughtermass[index]; + } + + //create parent G4DynamicParticle at rest + G4ThreeVector dummy; + G4DynamicParticle * parentparticle = new G4DynamicParticle( parent, dummy, 0.0); + //create G4Decayproducts + G4DecayProducts *products = new G4DecayProducts(*parentparticle); + delete parentparticle; + + // calculate daughter momentum + G4double daughtermomentum[3]; + // calcurate electron energy + G4double xmax = (1.0+daughtermass[0]*daughtermass[0]/parentmass/parentmass); + G4double x; + + G4double Ee,Ene; + + G4double gam; + G4double EMax=parentmass/2-daughtermass[0]; + + + //Generating Random Energy +do { + Ee=G4UniformRand(); + do{ + x=xmax*G4UniformRand(); + gam=G4UniformRand(); + }while (gam >x*(1.-x)); + Ene=x; + } while ( Ene < (1.-Ee)); + G4double Enm=(2.-Ee-Ene); + + + //initialisation of rotation parameters + + G4double costheta,sintheta,rphi,rtheta,rpsi; + costheta= 1.-2./Ee-2./Ene+2./Ene/Ee; + sintheta=std::sqrt(1.-costheta*costheta); + + + rphi=twopi*G4UniformRand()*rad; + rtheta=(std::acos(2.*G4UniformRand()-1.)); + rpsi=twopi*G4UniformRand()*rad; + + G4RotationMatrix rot; + rot.set(rphi,rtheta,rpsi); + + //electron 0 + daughtermomentum[0]=std::sqrt(Ee*Ee*EMax*EMax+2.0*Ee*EMax * daughtermass[0]); + G4ThreeVector direction0(0.0,0.0,1.0); + + direction0 *= rot; + + G4DynamicParticle * daughterparticle = new G4DynamicParticle ( daughters[0], direction0 * daughtermomentum[0]); + + products->PushProducts(daughterparticle); + + //electronic neutrino 1 + + daughtermomentum[1]=std::sqrt(Ene*Ene*EMax*EMax+2.0*Ene*EMax * daughtermass[1]); + G4ThreeVector direction1(sintheta,0.0,costheta); + + direction1 *= rot; + + G4DynamicParticle * daughterparticle1 = new G4DynamicParticle ( daughters[1], direction1 * daughtermomentum[1]); + products->PushProducts(daughterparticle1); + + //muonic neutrino 2 + + daughtermomentum[2]=std::sqrt(Enm*Enm*EMax*EMax +2.0*Enm*EMax*daughtermass[2]); + G4ThreeVector direction2(-Ene/Enm*sintheta,0,-Ee/Enm-Ene/Enm*costheta); + + direction2 *= rot; + + G4DynamicParticle * daughterparticle2 = new G4DynamicParticle ( daughters[2], + direction2 * daughtermomentum[2]); + products->PushProducts(daughterparticle2); + + + + + // output message +#ifdef G4VERBOSE + if (GetVerboseLevel()>1) { + G4cout << "MuDecayChannel::DecayIt "; + G4cout << " create decay products in rest frame " <DumpInfo(); + } +#endif + return products; +} + + + + + + diff --git a/src/MuDecayChannelWithSpin.cc b/src/MuDecayChannelWithSpin.cc new file mode 100644 index 0000000..5408d01 --- /dev/null +++ b/src/MuDecayChannelWithSpin.cc @@ -0,0 +1,271 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// ------------------------------------------------------------ +// GEANT 4 class header file +// +// History: +// 17 August 2004 P.Gumplinger and T.MacPhail +// samples Michel spectrum including 1st order +// radiative corrections +// Reference: Florian Scheck "Muon Physics", in Physics Reports +// (Review Section of Physics Letters) 44, No. 4 (1978) +// 187-248. North-Holland Publishing Company, Amsterdam +// at page 210 cc. +// +// W.E. Fisher and F. Scheck, Nucl. Phys. B83 (1974) 25. +// +// ------------------------------------------------------------ +// +#include "MuDecayChannelWithSpin.hh" + +#include "Randomize.hh" +#include "G4DecayProducts.hh" +#include "G4LorentzVector.hh" + +MuDecayChannelWithSpin::MuDecayChannelWithSpin(const G4String& theParentName, + G4double theBR) + : MuDecayChannel(theParentName,theBR) +{ +} + +MuDecayChannelWithSpin::~MuDecayChannelWithSpin() +{ +} + +G4DecayProducts *MuDecayChannelWithSpin::DecayIt(G4double) +{ + // This version assumes V-A coupling with 1st order radiative correctons, + // the standard model Michel parameter values, but + // gives incorrect energy spectrum for neutrinos + +#ifdef G4VERBOSE + if (GetVerboseLevel()>1) G4cout << "MuDecayChannelWithSpin::DecayIt "; +#endif + + if (parent == 0) FillParent(); + if (daughters == 0) FillDaughters(); + + // parent mass + G4double parentmass = parent->GetPDGMass(); + + EMMU = parentmass; + + //daughters'mass + G4double daughtermass[3]; + G4double sumofdaughtermass = 0.0; + for (G4int index=0; index<3; index++){ + daughtermass[index] = daughters[index]->GetPDGMass(); + sumofdaughtermass += daughtermass[index]; + } + + EMASS = daughtermass[0]; + + //create parent G4DynamicParticle at rest + G4ThreeVector dummy; + G4DynamicParticle * parentparticle = new G4DynamicParticle( parent, dummy, 0.0); + //create G4Decayproducts + G4DecayProducts *products = new G4DecayProducts(*parentparticle); + delete parentparticle; + + // calcurate electron energy + + G4double michel_rho = 0.75; //Standard Model Michel rho + G4double michel_delta = 0.75; //Standard Model Michel delta + G4double michel_xsi = 1.00; //Standard Model Michel xsi + G4double michel_eta = 0.00; //Standard Model eta + + G4double rndm, x, ctheta; + + G4double FG; + G4double FG_max = 2.00; + + G4double W_mue = (EMMU*EMMU+EMASS*EMASS)/(2.*EMMU); + G4double x0 = EMASS/W_mue; + + G4double x0_squared = x0*x0; + + // *************************************************** + // x0 <= x <= 1. and -1 <= y <= 1 + // + // F(x,y) = f(x)*g(x,y); g(x,y) = 1.+g(x)*y + // *************************************************** + + // ***** sampling F(x,y) directly (brute force) ***** + + do{ + + // Sample the positron energy by sampling from F + + rndm = G4UniformRand(); + + x = x0 + rndm*(1.-x0); + + G4double x_squared = x*x; + + G4double F_IS, F_AS, G_IS, G_AS; + + F_IS = 1./6.*(-2.*x_squared+3.*x-x0_squared); + F_AS = 1./6.*std::sqrt(x_squared-x0_squared)*(2.*x-2.+std::sqrt(1.-x0_squared)); + + G_IS = 2./9.*(michel_rho-0.75)*(4.*x_squared-3.*x-x0_squared); + G_IS = G_IS + michel_eta*(1.-x)*x0; + + G_AS = 3.*(michel_xsi-1.)*(1.-x); + G_AS = G_AS+2.*(michel_xsi*michel_delta-0.75)*(4.*x-4.+std::sqrt(1.-x0_squared)); + G_AS = 1./9.*std::sqrt(x_squared-x0_squared)*G_AS; + + F_IS = F_IS + G_IS; + F_AS = F_AS + G_AS; + + // *** Radiative Corrections *** + + G4double R_IS = F_c(x,x0); + + G4double F = 6.*F_IS + R_IS/std::sqrt(x_squared-x0_squared); + + // *** Radiative Corrections *** + + G4double R_AS = F_theta(x,x0); + + rndm = G4UniformRand(); + + ctheta = 2.*rndm-1.; + + G4double G = 6.*F_AS - R_AS/std::sqrt(x_squared-x0_squared); + + FG = std::sqrt(x_squared-x0_squared)*F*(1.+(G/F)*ctheta); + + if(FG>FG_max){ + G4cout<<"***Problem in Muon Decay *** : FG > FG_max"<PushProducts(daughterparticle0); + + + // daughter 1 ,2 (neutrinos) + // create neutrinos in the C.M frame of two neutrinos + G4double energy2 = parentmass*(1.0 - x/2.0); + G4double vmass = std::sqrt((energy2-daughtermomentum[0])*(energy2+daughtermomentum[0])); + G4double beta = -1.0*daughtermomentum[0]/energy2; + G4double costhetan = 2.*G4UniformRand()-1.0; + G4double sinthetan = std::sqrt((1.0-costhetan)*(1.0+costhetan)); + G4double phin = twopi*G4UniformRand()*rad; + G4double sinphin = std::sin(phin); + G4double cosphin = std::cos(phin); + + G4ThreeVector direction1(sinthetan*cosphin,sinthetan*sinphin,costhetan); + G4DynamicParticle * daughterparticle1 + = new G4DynamicParticle( daughters[1], direction1*(vmass/2.)); + G4DynamicParticle * daughterparticle2 + = new G4DynamicParticle( daughters[2], direction1*(-1.0*vmass/2.)); + + // boost to the muon rest frame + G4LorentzVector p4; + p4 = daughterparticle1->Get4Momentum(); + p4.boost( direction0.x()*beta, direction0.y()*beta, direction0.z()*beta); + daughterparticle1->Set4Momentum(p4); + p4 = daughterparticle2->Get4Momentum(); + p4.boost( direction0.x()*beta, direction0.y()*beta, direction0.z()*beta); + daughterparticle2->Set4Momentum(p4); + products->PushProducts(daughterparticle1); + products->PushProducts(daughterparticle2); + daughtermomentum[1] = daughterparticle1->GetTotalMomentum(); + daughtermomentum[2] = daughterparticle2->GetTotalMomentum(); + + // output message +#ifdef G4VERBOSE + if (GetVerboseLevel()>1) { + G4cout << "MuDecayChannelWithSpin::DecayIt "; + G4cout << " create decay products in rest frame " <DumpInfo(); + } +#endif + return products; +} + +G4double MuDecayChannelWithSpin::R_c(G4double x){ + + G4int n_max = (int)(100.*x); + + if(n_max<10)n_max=10; + + G4double L2 = 0.0; + + for(G4int n=1; n<=n_max; n++){ + L2 += std::pow(x,n)/(n*n); + } + + G4double omega = std::log(EMMU/EMASS); + + G4double r_c; + + r_c = 2.*L2-(pi*pi/3.)-2.; + r_c = r_c + omega * (1.5+2.*std::log((1.-x)/x)); + r_c = r_c - std::log(x)*(2.*std::log(x)-1.); + r_c = r_c + (3.*std::log(x)-1.-1./x)*std::log(1.-x); + + return r_c; +} diff --git a/src/meyer.cc b/src/meyer.cc new file mode 100644 index 0000000..6c4d489 --- /dev/null +++ b/src/meyer.cc @@ -0,0 +1,1032 @@ +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$//* +// LOW ENERGY MUON SPIN RELAXATION, ROTATION, RADIATION Geant4 SIMULATION +// ID : MEYER.cc , v 1.0 +// AUTHOR: Taofiq PARAISO +// DATE : 2005-04 +// +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$// +// +// & &&&&&&&&&& &&&&&&& &&&&&&&& +// & & && && & && +// & & & & & & && +// & &&&&&&& & & &&&&&& &&&&&&&& +// & & & && & & && +// & & && & & && && & & +// &&&&&&&&&& &&&&&&&&&& & &&&&& && &&&&&&& & && +// & +// & +// & +// & +// MEYER +/* + fIRST IMPLEMENTATION BY ANLSEM,H. IN FORTRAN + C++ CONVERSION T.K.PARAISO 04-2005 + + !!! IMPORTANT !!! + + Notice: + Tables definition changes between FORTRAN and C++: + 1/ Fortran indices start at 1 and C++ indices start at 0 + 2/ Tables are defined as table[column][row] in Fortran + table[row][column] in c++ + + usefull reference + http://gershwin.ens.fr/vdaniel/Doc-Locale/Langages-Program-Scientific/Fortran/Tutorial/arrays.htm + +*/ +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$// + + +#include "meyer.hh" +#include +#include +#include +#include +#include +using namespace std; + +meyer::meyer() +{;} + +meyer::~meyer() +{;} + +void meyer::GFunctions(double* g1,double* g2, double tau) +{ + + //Diese Routine gibt in Abhaengigkeit von der reduzierten Dicke 'tau' + //Funktionswerte fuer g1 und g2 zurueck. g1 und g2 sind dabei die von + //Meyer angegebenen tabellierten Funktionen fuer die Berechnung von Halbwerts- + //breiten von Streuwinkelverteilungen. (L.Meyer, phys.stat.sol. (b) 44, 253 + //(1971)) + + + double help; + + int i; + + + double tau_[] = {0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, + 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, + 10.0, 12.0, 14.0, 16.0, 18.0, 20.0 }; + + double g1_[] = {0.050,0.115,0.183,0.245,0.305,0.363,0.419,0.473,0.525,0.575, + 0.689,0.799,0.905,1.010,1.100,1.190,1.370,1.540,1.700,1.850, + 1.990,2.270,2.540,2.800,3.050,3.290 }; + + double g2_[] = {0.00,1.25,0.91,0.79,0.73,0.69,0.65,0.63,0.61,0.59, + 0.56,0.53,0.50,0.47,0.45,0.43,0.40,0.37,0.34,0.32, + 0.30,0.26,0.22,0.18,0.15,0.13 }; + + + if (tau kann ich nicht ... => STOP"< Tabelle A + thetaSchlangeMax = 4.0; + } + else if (tau<=8.) + { + //! => Tabelle B + thetaSchlangeMax = 7.0; + } + else if (tau<=20.) + { + //! => Tabelle C + thetaSchlangeMax = 20.0; + } + else + { + std::cout<< "Subroutine ''Get_F_Function_Meyer'':"< kann ich nicht ... => STOP"<50.) + { + thetaStep = .5; + } + + else if (thetaMax>25) + { + thetaStep = .25; + } + else if (thetaMax>12.5) + { + thetaStep = .125; + } + else + { + thetaStep = .0625; + } + + + //Tabelle der F-Werte erstellen: + + nBin = 0; + std::cout<<"thetamax = "<nBinMax) + { + std::cout<< "nBin > nBinMax => EXIT"; + break; + } + + value[nBin] = sin(theta)*F; + + fValues[nBin+1] = F; // ! fuer Testzwecke + fValuesFolded[nBin+1] = sin(theta/180*M_PI)*F;// ! fuer Testzwecke + + + }// end of do loop + + + //Berechnen der Flaecheninhalte der einzelnen Kanaele sowie der Integrale: + + bigtheta:for( i = 1;i<= nBin; i++) + { + area[i] = (value[i]+value[i-1])/2.* thetaStep; + integ[i] = integ[i-1] + area[i]; + } + + + //Normiere totale Flaeche auf 1: + + rHelp = integ[nBin]; + for( i = 1; i<=nBin; i++) + { + value[i] = value[i] / rHelp; + area[i] = area[i] / rHelp; + integ[i] = integ[i] / rHelp; + } + + + //vorerst noch: gib Tabelle in Datei und Histogrammfile aus: + + //! Berechne die Werte fuer theta=0: + + F_Functions_Meyer(tau,0.,&f1,&f2); + F = Meyer_faktor4*Meyer_faktor4 * Ekin*Ekin /2 /M_PI * (f1 - Meyer_faktor3*f2);// TAO, Anselm was: Meyer_faktor5 * Ekin*Ekin * (f1 - Meyer_faktor3*f2); + fValues[1] = F; + fValuesFolded[1] = 0.; + + //! Gib die Werte in das Tabellenfile aus: + + /* ofstream Mprint("testmeyer.out"); + theta = thetaStep; + if (!Mprint.is_open()) exit(8); + for( i = 1; i<=nBin+1;i++) + { + Mprint << theta<< " "<< fValues[i]/fValues[1]<<" " << fValuesFolded[i]< Reihe mit hoeherem Index + //iColumn = 2 => Reihe mit kleinerem Index + + + iColumn = 1; + + // 5 continue; + do{ + + if (column_<=8) + { + //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //! Werte aus 1. Tabelle: 0.2 <= tau <= 1.8 + + column = column_; + // std::cout<<"thetaSchlange = "<OpenGeometry(); + G4PhysicalVolumeStore::GetInstance()->Clean(); + G4LogicalVolumeStore::GetInstance()->Clean(); + G4SolidStore::GetInstance()->Clean(); + + // G4cout<< "musrDetectorConstruction::Construct: ParameterFileName="<rotateY(90.0*deg); + } + + G4FieldManager* pFieldMan = pointerToField[actualFieldName]; + if (pFieldMan!=NULL) {G4cout<<" volume with field, ";} + else if ((strcmp(actualFieldName,"nofield"))) { + G4cout <<"Field Manager \""<SetLogicalVolumeAsSpecialSaveVolume(logicName,volumeID); + musrRootOutput::GetRootInstance()->SetSpecialSaveVolumeDefined(); + } + } + + // Unless specified as "dead", set the volume sensitive volume: + if (strcmp(sensitiveDet,"dead")) { + if (strcmp(sensitiveDet,"musr/ScintSD")==0) { + if(!aScintSD) { + G4SDManager* SDman = G4SDManager::GetSDMpointer(); + G4String scintSDname = sensitiveDet; + aScintSD = new musrScintSD( scintSDname ); + SDman->AddNewDetector( aScintSD ); + G4cout<<"musrDetectorConstruction.cc: aScintSD added: "<GetFullPathName()<SetSensitiveDetector( aScintSD ); + } + else { + G4cout<<" musrDetectorConstruction.cc: unknown sensitive detector \""<SetVolumeIDMapping(logicName,volumeID); + } + + // If the volume name is "Target", "M0", "M1" or "M2", let's save muon polarisation and time in these volumes: + if ((strcmp(name,"Target")==0)||(strcmp(name,"target")==0)) { + musrRootOutput::store_muTargetTime = true; musrRootOutput::store_muTargetPolX = true; + musrRootOutput::store_muTargetPolY = true; musrRootOutput::store_muTargetPolZ = true; + } + if ((strcmp(name,"M0")==0)||(strcmp(name,"m0")==0)) { + musrRootOutput::store_muM0Time = true; musrRootOutput::store_muM0PolX = true; + musrRootOutput::store_muM0PolY = true; musrRootOutput::store_muM0PolZ = true; + } + if ((strcmp(name,"M1")==0)||(strcmp(name,"m1")==0)) { + musrRootOutput::store_muM1Time = true; musrRootOutput::store_muM1PolX = true; + musrRootOutput::store_muM1PolY = true; musrRootOutput::store_muM1PolZ = true; + } + if ((strcmp(name,"M2")==0)||(strcmp(name,"m2")==0)) { + musrRootOutput::store_muM2Time = true; musrRootOutput::store_muM2PolX = true; + musrRootOutput::store_muM2PolY = true; musrRootOutput::store_muM2PolZ = true; + } + } + + else if (strcmp(tmpString1,"visattributes")==0){ + sscanf(&line[0],"%*s %*s %*s %s",tmpString3); + if (strncmp(tmpString2,"log_",4)==0) { + G4LogicalVolume* pLogVol = FindLogicalVolume(tmpString2); + if (pLogVol==NULL) { + sprintf(eMessage,"musrDetectorConstruction.cc::Construct(): visattributes requested for %s, but this volume was not found.",tmpString2); + musrErrorMessage::GetInstance()->musrError(WARNING,eMessage,false); + } + else {SetColourOfLogicalVolume(pLogVol,tmpString3);} + } + else { + G4LogicalVolumeStore* pLogStore = G4LogicalVolumeStore::GetInstance(); + if (pLogStore==NULL) { + G4cout<<"ERROR: musrDetectorConstruction.cc: G4LogicalVolumeStore::GetInstance() not found!"<size(); i++) { + G4LogicalVolume* pLogVol=pLogStore->at(i); + G4String materialName=pLogVol->GetMaterial()->GetName(); + if (tmpString2==materialName) { + SetColourOfLogicalVolume(pLogVol,tmpString3); + } + } + } + } + } + + // cks: Implementation of the Global Field (to allow overlapping fields) based + // on the Peter Gumplinger's implementation of G4BeamLine code into Geant4. + // + else if (strcmp(tmpString1,"globalfield")==0){ + // ensure the global field is initialized + // perhaps should be placed at some separate position ? + (void)F04GlobalField::getObject(); + + char typeOfField[100]="Unset"; + float pp1=0; float pp2=0; float pp3=0; + sscanf(&line[0],"%*s %*s %*s %g %g %g %s",&pp1,&pp2,&pp3,typeOfField); + G4ThreeVector position = G4ThreeVector(pp1,pp2,pp3); + float fieldValue=0.000000001; + float fieldValueFinal=0; + int fieldNrOfSteps=0; + // if (strcmp(tmpString2,"magnetic")==0){ + if (strcmp(typeOfField,"fromfile")==0) { + char fieldInputFileName[100]; + char fieldTableType[100]; + char logicalVolumeName[100]; + sscanf(&line[0],"%*s %*s %*s %*g %*g %*g %*s %s %s %s %g %g %d",fieldTableType,fieldInputFileName,logicalVolumeName, + &fieldValue,&fieldValueFinal,&fieldNrOfSteps); + // Find out the logical volume, to which the field will be placed: + G4LogicalVolume* logVol = FindLogicalVolume(logicalVolumeName); + if (logVol==NULL) { + sprintf(eMessage,"musrDetectorConstruction.cc::Construct(): GLOBAL FIELD: Logical volume \"%s\" not found.", + logicalVolumeName); + musrErrorMessage::GetInstance()->musrError(FATAL,eMessage,false); + } + + // Construct the field + musrTabulatedElementField* myElementTableField = + new musrTabulatedElementField(fieldInputFileName, fieldTableType, fieldValue*tesla, logVol, position); + myElementTableField->SetElementFieldName(tmpString2); + if (fieldNrOfSteps>0) { + //cks The following line might require some correction for the electric field + myElementTableField->SetEventNrDependentField(fieldValue*tesla,fieldValueFinal*tesla,fieldNrOfSteps); + } + // FieldList* fields = F04GlobalField::getObject()->getFields(); + // if (fields) { + // G4cout<<"DEBUG: Detector construction: fields->size()="<size()<musrError(FATAL,eMessage,false); + } + G4double fieldValue_tmp[6] = { + fieldValue[0]*tesla, fieldValue[1]*tesla, fieldValue[2]*tesla, + fieldValue[3]*(kilovolt/mm),fieldValue[4]*(kilovolt/mm),fieldValue[5]*(kilovolt/mm)}; + + musrUniformField* myElementUniformField = new musrUniformField(fieldValue_tmp, half_x, half_y, half_z, logVol, position); + myElementUniformField->SetElementFieldName(tmpString2); + } + + else if (strcmp(typeOfField,"quadrupole")==0) { + float halfLength, fieldRadius, gradientValue, gradientValueFinal, fringeFactor; + int gradientNrOfSteps; + char logicalVolumeName[100]; + sscanf(&line[0],"%*s %*s %*s %*g %*g %*g %*s %g %g %g %s %g %g %d",&halfLength,&fieldRadius,&fringeFactor,logicalVolumeName, + &gradientValue,&gradientValueFinal,&gradientNrOfSteps); + G4LogicalVolume* logVol = FindLogicalVolume(logicalVolumeName); + if (logVol==NULL) { + sprintf(eMessage,"musrDetectorConstruction.cc::Construct(): GLOBAL FIELD: Logical volume \"%s\" not found.", + logicalVolumeName); + musrErrorMessage::GetInstance()->musrError(FATAL,eMessage,false); + } + musrQuadrupole* myMusrQuadrupole = new musrQuadrupole(halfLength*mm,fieldRadius*mm,gradientValue*(tesla/m),fringeFactor,logVol,position); + myMusrQuadrupole->SetElementFieldName(tmpString2); + if (gradientNrOfSteps>0) { + myMusrQuadrupole->SetEventNrDependentField(gradientValue*(tesla/m),gradientValueFinal*(tesla/m),gradientNrOfSteps); + } + } + + else if (strcmp(tmpString2,"setparameter")==0){ + // First check that the magnetic field already exists: + G4FieldManager* fieldMgr = G4TransportationManager::GetTransportationManager()->GetFieldManager(); + G4PropagatorInField* propagMgr = G4TransportationManager::GetTransportationManager()->GetPropagatorInField(); + if (fieldMgr==NULL) { + ReportProblemInStearingFile(line); + sprintf(eMessage,"musrDetectorConstruction.cc::Construct(): G4FieldManager not found: fieldMgr=NULL"); + musrErrorMessage::GetInstance()->musrError(FATAL,eMessage,false); + } + if (propagMgr==NULL) { + ReportProblemInStearingFile(line); + sprintf(eMessage,"musrDetectorConstruction.cc::Construct(): G4PropagatorInField not found: propagMgr=NULL"); + musrErrorMessage::GetInstance()->musrError(FATAL,eMessage,false); + } + else { + char parameterName[100]; + float parameterValue; + sscanf(&line[0],"%*s %*s %*s %s %g",parameterName,¶meterValue); + if (strcmp(parameterName,"SetDeltaIntersection")==0){ fieldMgr->SetDeltaIntersection(parameterValue*mm); } + else if (strcmp(parameterName,"SetDeltaOneStep")==0){ fieldMgr->SetDeltaOneStep(parameterValue*mm); } + else if (strcmp(parameterName,"SetMinimumEpsilonStep")==0){ fieldMgr->SetMinimumEpsilonStep(parameterValue); } + else if (strcmp(parameterName,"SetMaximumEpsilonStep")==0){ fieldMgr->SetMaximumEpsilonStep(parameterValue); } + else if (strcmp(parameterName,"SetLargestAcceptableStep")==0) { propagMgr->SetLargestAcceptableStep(parameterValue*mm); } + else if (strcmp(parameterName,"SetMaxLoopCount")==0) {propagMgr->SetMaxLoopCount(int(parameterValue)); } + else { + G4cout<<"musrDetectorConstruction.cc: ERROR: Unknown parameterName \"" + <GetFieldManager(); + G4PropagatorInField* propagMgr = G4TransportationManager::GetTransportationManager()->GetPropagatorInField(); + if (fieldMgr==NULL) { + G4cout<<"musrDetectorConstruction: ERROR: Field manager not found!"<AddPointForFieldTesting(G4ThreeVector(p0,p1,p2)); + } + else { + sprintf(eMessage,"musrDetectorConstruction.cc::Construct(): printFieldValueAtPoint requested, but field not found"); + musrErrorMessage::GetInstance()->musrError(SERIOUS,eMessage,false); + } + } + } + + else {ReportGeometryProblem(line);} + } + + + // Set range cut for a given volume, if requested by the macro file + else if (strcmp(tmpString1,"SetUserLimits")==0){ + G4LogicalVolume* pLogVol = FindLogicalVolume(tmpString2); + if (pLogVol==NULL) { + G4cout << "ERROR! musrDetectorConstruction::Construct(): SetUserLimits: Logical Volume \"" + << tmpString3 <<"\" not found!"<0) {myUserLimits->SetMaxAllowedStep(ustepMax*mm); G4cout<<"ustepMax = "<0) {myUserLimits->SetUserMaxTrackLength(utrakMax*mm);G4cout<<"utrakMax = "<0) {myUserLimits->SetUserMaxTime(utimeMax*ns); G4cout<<"utimeMax = "<0) {myUserLimits->SetUserMinEkine(uekinMin*MeV); G4cout<<"uekinMin = "<0) {myUserLimits->SetUserMinRange(urangMin*mm); G4cout<<"urangMin = "<SetUserLimits(myUserLimits); + } + + + else if (strcmp(tmpString1,"storeOnlyEventsWithHitInDetID")==0){ + G4int variable; + sscanf(&line[0],"%*s %*s %d",&variable); + if (variable!=0){ + musrParameters::storeOnlyEventsWithHits = true; + musrParameters::storeOnlyEventsWithHitInDetID = variable; + char eMessage[200]; + sprintf(eMessage, + "musrDetectorConstruction.cc:: Only the events with at least one hit in the detector ID=%d are stored", + variable); + musrErrorMessage::GetInstance()->musrError(INFO,eMessage,false); + } + } + + else if (strcmp(tmpString1,"storeOnlyEventsWithHits")==0){ + if (strcmp(tmpString2,"false")==0){ musrParameters::storeOnlyEventsWithHits = false; } + } + + else if (strcmp(tmpString1,"storeOnlyTheFirstTimeHit")==0){ + if (strcmp(tmpString2,"true")==0){ musrParameters::storeOnlyTheFirstTimeHit = true; } + } + + else if (strcmp(tmpString1,"killAllPositrons")==0){ + if (strcmp(tmpString2,"true")==0){ musrParameters::killAllPositrons = true; } + else { musrParameters::killAllPositrons = false; } + } + + else if (strcmp(tmpString1,"killAllGammas")==0){ + if (strcmp(tmpString2,"true")==0){ musrParameters::killAllGammas = true; } + else { musrParameters::killAllGammas = false; } + } + + else if (strcmp(tmpString1,"killAllNeutrinos")==0){ + if (strcmp(tmpString2,"true")==0){ musrParameters::killAllNeutrinos = true; } + else { musrParameters::killAllNeutrinos = false; } + } + + else if (strcmp(tmpString1,"getDetectorMass")==0){ + G4LogicalVolume* massVol = FindLogicalVolume(tmpString2); + if (massVol==NULL) { + G4cout << "ERROR! musrDetectorConstruction::Construct(): Logical Volume \"" + << tmpString3 <<"\" not found!"<GetMass()/kg<<" kg."< SetVolumeForMuonEventReweighting(G4String(tmpLogVolName),eventWeight); + } + else { + sprintf(eMessage, + "musrDetectorConstruction.cc:: logicalVolumeToBeReweighted - reweighting for particle %s not yet implemented", + tmpString2); + musrErrorMessage::GetInstance()->musrError(FATAL,eMessage,true); + } + } + + // Set G4Regions - intended mainly for the coulomb scattering or special production cuts (added on 2008.08.21) + else if (strcmp(tmpString1,"region")==0) { + if (strcmp(tmpString2,"define")==0) { + char charRegionName[100]; + char charLogicalVolumeName[100]; + sscanf(&line[0],"%*s %*s %*s %s %s",charRegionName,charLogicalVolumeName); + G4String regionName = charRegionName; + G4String logicalVolumeName = charLogicalVolumeName; + + G4Region* myRegion = G4RegionStore::GetInstance()->GetRegion(regionName,false); + if( myRegion == NULL ) { // First time - instantiate a region and a cut objects + myRegion = new G4Region(regionName); + G4cout<<"musrDetectorConstruction: G4Region "<SetProductionCuts(cuts); + } + else {G4cout<<"musrDetectorConstruction: G4Region "<GetProductionCuts(); + // } + G4LogicalVolume* logicalVolume = FindLogicalVolume(logicalVolumeName); + if (logicalVolume != NULL) { + myRegion->AddRootLogicalVolume(logicalVolume); + G4cout<<" and volume "<musrError(SERIOUS,eMessage,false); + } + } + else if (strcmp(tmpString2,"setProductionCut")==0) { + char charRegionName[100]; + float fGammaCut=0, fElectronCut=0, fPositronCut=0; + sscanf(&line[0],"%*s %*s %*s %s %g %g %g",charRegionName,&fGammaCut,&fElectronCut,&fPositronCut); + G4String regionName = charRegionName; + G4Region* myRegion = G4RegionStore::GetInstance()->GetRegion(regionName,false); + if( myRegion == NULL ) { // G4Region does not exist + G4cout<<"musrDetectorConstruction: setProductionCut required for the G4Region "<SetProductionCuts(cuts); + } + else { // G4Region exists, so set the cuts: + G4ProductionCuts* cuts = myRegion->GetProductionCuts(); + if (cuts==NULL) {G4cout<<"musrDetectorConstruction: DEBUG - ERROR !!!! cuts for G4Region not defined!!!!"<SetProductionCut(fGammaCut,"gamma"); + if (fElectronCut!=0) cuts->SetProductionCut(fElectronCut,"e-"); + if (fPositronCut!=0) cuts->SetProductionCut(fPositronCut,"e+"); + } + } + } + else { + G4cout << "ERROR! musrDetectorConstruction::Construct(): Unknown command requested for the \"region\" keyword."<SetCalculationOfFieldIntegralRequested(true); + } + } + } + + else if (strcmp(tmpString1,"process")==0) { + ; // processes are interpreded later in musrPhysicsList.cc + } + + + else ReportGeometryProblem(line); + + } + } + fclose(fSteeringFile); + // G4cout<< "musrDetectorConstruction.cc: pointerToWorldVolume="<FindOrBuildElement("H"); + G4Element* C = man->FindOrBuildElement("C"); + G4Element* N = man->FindOrBuildElement("N"); + G4Element* O = man->FindOrBuildElement("O"); + // Elements required for Brass + G4Element* Cu = man->FindOrBuildElement("Cu"); + G4Element* Zn = man->FindOrBuildElement("Zn"); + // elements required for Stainless Steel + G4Element* Cr = man->FindOrBuildElement("Cr"); + G4Element* Fe = man->FindOrBuildElement("Fe"); + G4Element* Ni = man->FindOrBuildElement("Ni"); + // Elements required for MCPglass + G4Element* Pb = man->FindOrBuildElement("Pb"); + G4Element* Si = man->FindOrBuildElement("Si"); + G4Element* K = man->FindOrBuildElement("K" ); + G4Element* Rb = man->FindOrBuildElement("Rb"); + G4Element* Ba = man->FindOrBuildElement("Ba"); + G4Element* As = man->FindOrBuildElement("As"); + G4Element* Cs = man->FindOrBuildElement("Cs"); + G4Element* Na = man->FindOrBuildElement("Na"); + + // Elements required for Macor + G4Element* B = man->FindOrBuildElement("B" ); + G4Element* Al = man->FindOrBuildElement("Al"); + G4Element* Mg = man->FindOrBuildElement("Mg"); + + // compounds required for MCP Macor + G4Material* MgO = new G4Material("MgO", 3.60*g/cm3, ncomponents=2); + MgO->AddElement(Mg, natoms=1); + MgO->AddElement(O, natoms=1); + + G4Material* SiO2 = new G4Material("SiO2", 2.533*g/cm3, ncomponents=2); // quartz + SiO2->AddElement(O, natoms=2); + SiO2->AddElement(Si, natoms=1); + + G4Material* Al2O3 = new G4Material("Al2O3", 3.985*g/cm3, ncomponents=2); // saphire + Al2O3->AddElement (Al, natoms=2); + Al2O3->AddElement (O, natoms=3); + + G4Material* K2O = new G4Material("K2O", 2.350*g/cm3, ncomponents=2); + K2O->AddElement(O, natoms=1); + K2O->AddElement(K, natoms=2); + + G4Material* B2O3 = new G4Material("B2O3", 2.550*g/cm3, ncomponents=2); + B2O3->AddElement (B, natoms=2); + B2O3->AddElement (O, natoms=3); + + G4Material* Sci = + new G4Material("Scintillator", density= 1.032*g/cm3, ncomponents=2); + Sci->AddElement(C, natoms=9); + Sci->AddElement(H, natoms=10); + + G4Material* Myl = + new G4Material("Mylar", density= 1.397*g/cm3, ncomponents=3); + Myl->AddElement(C, natoms=10); + Myl->AddElement(H, natoms= 8); + Myl->AddElement(O, natoms= 4); + + // Brass + G4Material* brass = new G4Material("Brass", density= 8.40*g/cm3, ncomponents=2); + brass -> AddElement(Zn, fractionmass = 30*perCent); + brass -> AddElement(Cu, fractionmass = 70*perCent); + + // Stainless steel + G4Material* steel = new G4Material("Steel", density= 7.93*g/cm3, ncomponents=3); + steel->AddElement(Ni, fractionmass=0.11); + steel->AddElement(Cr, fractionmass=0.18); + steel->AddElement(Fe, fractionmass=0.71); + + G4Material* macor= // Macor (used in the MCP detector) + new G4Material("Macor", density=2.52*g/cm3, ncomponents=5); + macor->AddMaterial(SiO2, fractionmass=0.470); // quartz + macor->AddMaterial(MgO, fractionmass=0.180); + macor->AddMaterial(Al2O3,fractionmass=0.170); // saphire + macor->AddMaterial(K2O, fractionmass=0.105); + macor->AddMaterial(B2O3, fractionmass=0.075); + + G4Material* mcpglass = // Glass of the Multi Channel Plate + new G4Material("MCPglass", density=2.0*g/cm3, ncomponents=9); + mcpglass->AddElement(Pb, fractionmass= 0.480); + mcpglass->AddElement(O, fractionmass= 0.258); + mcpglass->AddElement(Si, fractionmass= 0.182); + mcpglass->AddElement(K, fractionmass= 0.042); + mcpglass->AddElement(Rb, fractionmass= 0.018); + mcpglass->AddElement(Ba, fractionmass= 0.013); + mcpglass->AddElement(As, fractionmass= 0.004); + mcpglass->AddElement(Cs, fractionmass= 0.002); + mcpglass->AddElement(Na, fractionmass= 0.001); + +// +// define a material from elements. case 2: mixture by fractional mass +// + + G4Material* Air = + new G4Material("Air" , density= 1.290*mg/cm3, ncomponents=2); + Air->AddElement(N, fractionmass=0.7); + Air->AddElement(O, fractionmass=0.3); + +// +// examples of vacuum +// + +// G4Material* Vacuum = + new G4Material("Vacuum", z=1., a=1.01*g/mole,density= universe_mean_density, + kStateGas, 2.73*kelvin, 3.e-18*pascal); + + new G4Material("ArgonGas", z= 18., a= 39.95*g/mole, density= 0.00000000001*mg/cm3); + + if (musrParameters::boolG4OpticalPhotons) { + G4NistManager* man = G4NistManager::Instance(); + G4Material* scintik = man->FindOrBuildMaterial("G4_PLASTIC_SC_VINYLTOLUENE"); + // G4Material* scintik = G4Material::GetMaterial("G4_PLASTIC_SC_VINYLTOLUENE"); + G4cout<<"scintik="<AddProperty("RINDEX", PhotonEnergy, RefractiveIndex, nEntries); + myMPT1->AddProperty("ABSLENGTH", PhotonEnergy, Absorption, nEntries); + myMPT1->AddProperty("FASTCOMPONENT", PhotonEnergy, ScintilFast, nEntries); + myMPT1->AddProperty("SLOWCOMPONENT", PhotonEnergy, ScintilSlow, nEntries); + myMPT1->AddConstProperty("SCINTILLATIONYIELD", 8400./MeV); + myMPT1->AddConstProperty("RESOLUTIONSCALE",1.0); + myMPT1->AddConstProperty("FASTTIMECONSTANT",1.6*ns); + myMPT1->AddConstProperty("SLOWTIMECONSTANT",1.6*ns); + myMPT1->AddConstProperty("YIELDRATIO",1.0); + scintik->SetMaterialPropertiesTable(myMPT1); + + scintik->GetMaterialPropertiesTable()->DumpTable(); + } + G4cout<<"OK konec"<DefineWorldVolume(Construct()); +} + + +void musrDetectorConstruction::ReportGeometryProblem(char myString[501]) { + G4cout<<"\nE R R O R in musrDetectorConstruction.cc: " + <<"Unknown keyword requested in \""<< parameterFileName <<"\" :"<FindOrBuildMaterial(materialName); + if (Material==NULL) { + G4cout<<"\nE R R O R in musrDetectorConstruction.cc::CharToMaterial " + <<"Unknown material requested:"<entries(); i++) { + for (unsigned int i=0; isize(); i++) { + G4LogicalVolume* pLogVol=pLogStore->at(i); + G4String iLogName=pLogVol->GetName(); + if (iLogName==LogicalVolumeName) { + return pLogVol; + } + } + } + return NULL; +} + +void musrDetectorConstruction::SetColourOfLogicalVolume(G4LogicalVolume* pLogVol,char* colour) { + if (pLogVol!=NULL) { + if (strcmp(colour,"red" )==0) {pLogVol->SetVisAttributes(G4Colour(1,0,0));} + else if (strcmp(colour,"green" )==0) {pLogVol->SetVisAttributes(G4Colour(0,1,0));} + else if (strcmp(colour,"blue" )==0) {pLogVol->SetVisAttributes(G4Colour(0,0,1));} + else if (strcmp(colour,"lightblue")==0) {pLogVol->SetVisAttributes(G4Colour(0,1,1));} + else if (strcmp(colour,"white" )==0) {pLogVol->SetVisAttributes(G4Colour(1,1,1));} + else if (strcmp(colour,"yellow" )==0) {pLogVol->SetVisAttributes(G4Colour(1,1,0));} + else if (strcmp(colour,"black" )==0) {pLogVol->SetVisAttributes(G4Colour(0,0,0));} + else if (strcmp(colour,"gray" )==0) {pLogVol->SetVisAttributes(G4Colour(0.5,0.5,0.5));} + else if (strcmp(colour,"cyan" )==0) {pLogVol->SetVisAttributes(G4Colour(0,1,1));} + else if (strcmp(colour,"magenta")==0) {pLogVol->SetVisAttributes(G4Colour(1,0,1));} + else if (strcmp(colour,"invisible" )==0) {pLogVol->SetVisAttributes(G4VisAttributes::Invisible);} + + else if (strcmp(colour,"blue_style")==0) {pLogVol->SetVisAttributes(G4Colour(0.80,0.83,1));} + else if (strcmp(colour,"lightblue")==0) {pLogVol->SetVisAttributes(G4Colour(0,0.5,1));} + else if (strcmp(colour,"darkblue")==0) {pLogVol->SetVisAttributes(G4Colour(0,0.25,0.5));} + else if (strcmp(colour,"fblue_style")==0) {pLogVol->SetVisAttributes(G4Colour(0.85,.88,0.92));} + else if (strcmp(colour,"oxsteel")==0) {pLogVol->SetVisAttributes(G4Colour(0.9,0.8,0.75));} + else if (strcmp(colour,"darkred")==0) {pLogVol->SetVisAttributes(G4Colour(0.5,0,0));} + else if (strcmp(colour,"MCP_style")==0) {pLogVol->SetVisAttributes(G4Colour(0.5,0.2,.7));} + else if (strcmp(colour,"MACOR_style")==0) {pLogVol->SetVisAttributes(G4Colour(0.9,0.9,.1));} + else if (strcmp(colour,"SCINT_style")==0) {pLogVol->SetVisAttributes(G4Colour(0.5,0.5,.75));} + else if (strcmp(colour,"dSCINT_style")==0) {pLogVol->SetVisAttributes(G4Colour(0.3,0.3,0.3));} + else if (strcmp(colour,"VTBB_style")==0) {pLogVol->SetVisAttributes(G4Colour(0.9,0.9,.9));} + else if (strcmp(colour,"Grid_style")==0) {pLogVol->SetVisAttributes(G4Colour(0.87,0.72,0.53));} //burlywood + else if (strcmp(colour,"RA_style")==0) {pLogVol->SetVisAttributes(G4Colour(0.8549,0.6471,0.1255));} //goldenrod + + else { + G4cout<<"ERROR: musrDetectorConstruction::SetColourOfLogicalVolume: unknown colour requested: "< //cks -----------------------------||------------------------------- +#include "musrEventAction.hh" // cks needed for setting the variable "nHowOftenToPrintEvent" +#include "musrPrimaryGeneratorAction.hh" // cks needed for the initialisation of the random nr. generator by event nr. +#include +#include "globals.hh" + + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + + +musrDetectorMessenger::musrDetectorMessenger(musrDetectorConstruction* myDet) + :myDetector(myDet) +{ + musrDir = new G4UIdirectory("/musr/"); + musrDir->SetGuidance("UI commands specific to this example."); + + Ignore1Cmd = new G4UIcmdWithAString("/musr/ignore",this); + Ignore1Cmd->SetGuidance("This command is ignored by the messenger, but used for the detector construction."); + Ignore1Cmd->AvailableForStates(G4State_PreInit,G4State_Idle); + + Ignore2Cmd = new G4UIcmdWithAString("/musr/command",this); + Ignore2Cmd->SetGuidance("This command is ignored by the messenger, but used for the detector construction."); + Ignore2Cmd->AvailableForStates(G4State_PreInit,G4State_Idle); + + runDir = new G4UIdirectory("/musr/run/"); + runDir->SetGuidance("musr run control"); + + RunIDSetCmd = new G4UIcmdWithAnInteger("/musr/run/runID",this); + RunIDSetCmd->SetGuidance("Set the run number"); + RunIDSetCmd->SetParameterName("something",false); + RunIDSetCmd->AvailableForStates(G4State_PreInit,G4State_Idle); + + RandomOptionCmd = new G4UIcmdWithAnInteger("/musr/run/randomOption",this); + RandomOptionCmd->SetGuidance("Specify the random number generator initialisation"); + RandomOptionCmd->SetGuidance(" 0 ... no initialisation (default)"); + RandomOptionCmd->SetGuidance(" 1 ... use actual computer time to initialise now"); + RandomOptionCmd->SetGuidance(" 2 ... use event number to initialise at the beginning of each event"); + RandomOptionCmd->SetGuidance(" 3 ... read in the random no. initial values for each event from a file"); + RandomOptionCmd->SetGuidance(" 4 ... read in the random no. initial values for each event from the file kamil.rndm"); + RandomOptionCmd->SetParameterName("randomOpt",false); + RandomOptionCmd->AvailableForStates(G4State_PreInit,G4State_Idle); + + HowOftenToPrintEventCmd = new G4UIcmdWithAnInteger("/musr/run/howOftenToPrintEvent",this); + HowOftenToPrintEventCmd->SetGuidance("Each n-th event will be notified. Set _n_ by this command."); + HowOftenToPrintEventCmd->SetParameterName("howOftenToPrintEv",false); + HowOftenToPrintEventCmd->AvailableForStates(G4State_PreInit,G4State_Idle); + + RndmEventToSaveSeedsCmd = new G4UIcmdWithAnInteger("/musr/run/rndmEventToSaveSeeds",this); + RndmEventToSaveSeedsCmd -> SetGuidance("Save seeds of the random number generators of the given event number."); + RndmEventToSaveSeedsCmd -> SetParameterName("rndmEventToSaveSe",false); + RndmEventToSaveSeedsCmd -> AvailableForStates(G4State_PreInit,G4State_Idle); + + detDir = new G4UIdirectory("/musr/det/"); + detDir->SetGuidance("detector control."); + + UpdateCmd = new G4UIcmdWithoutParameter("/musr/det/update",this); + UpdateCmd->SetGuidance("Update calorimeter geometry."); + UpdateCmd->SetGuidance("This command MUST be applied before \"beamOn\" "); + UpdateCmd->SetGuidance("if you changed geometrical value(s)."); + UpdateCmd->AvailableForStates(G4State_Idle); + +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +musrDetectorMessenger::~musrDetectorMessenger() +{ + delete UpdateCmd; + delete detDir; + delete musrDir; + delete Ignore1Cmd; + delete Ignore2Cmd; + delete RunIDSetCmd; + delete RandomOptionCmd; + delete HowOftenToPrintEventCmd; + delete RndmEventToSaveSeedsCmd; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrDetectorMessenger::SetNewValue(G4UIcommand* command,G4String newValue) { + + if( command == UpdateCmd ) + { myDetector->UpdateGeometry(); } + + if( command == RunIDSetCmd ) + { (G4RunManager::GetRunManager())->SetRunIDCounter(RunIDSetCmd->GetNewIntValue(newValue));} + + if( command == RandomOptionCmd ) + { + G4int RandomOption=RandomOptionCmd->GetNewIntValue(newValue); + if (RandomOption == 1) { + // G4long seed=time(0); //returns time in seconds as an integer + // HepRandom::setTheSeed(seed);//changes the seed of the random engine + G4cout << "******************************************" << G4endl; + G4cout << "*** Random Seed set by the system time ***" << G4endl; + G4cout << "******************************************" << G4endl; + long seeds[2]; + time_t systime = time(NULL); + seeds[0] = (long) systime; + seeds[1] = (long) (systime*G4UniformRand()); + G4cout << "seed1: " << seeds[0] << "; seed2: " << seeds[1] << G4endl; + CLHEP::HepRandom::setTheSeeds(seeds); + CLHEP::HepRandom::showEngineStatus(); + } + else if (RandomOption == 2) { + G4cout << "*******************************************" << G4endl; + G4cout << "*** Random Seed set by the event number ***" << G4endl; + G4cout << "*******************************************" << G4endl; + // musrEventAction::setRandomNrSeedAccordingEventNr=1; + musrPrimaryGeneratorAction::setRandomNrSeedAccordingEventNr=1; + // musrEventAction::setMyEventNr(70); + } + else if (RandomOption == 3) { + G4cout << "*******************************************" << G4endl; + G4cout << "*** Random Seed set from external file ***" << G4endl; + G4cout << "*******************************************" << G4endl; + // musrEventAction::setRandomNrSeedFromFile=1; + musrPrimaryGeneratorAction::setRandomNrSeedFromFile=1; + std::ifstream indata; + int num; + + indata.open("randomNum.dat"); // opens the file + if(!indata) { // file couldn't be opened + G4cout << "Error: file could not be opened" << G4endl; + exit(1); + } + std::vector * seedVector = musrPrimaryGeneratorAction::GetPointerToSeedVector(); + indata >> num; + while ( !indata.eof() ) { // keep reading until end-of-file + G4cout << "The next number is " << num << G4endl; + seedVector->push_back(num); + indata >> num; // sets EOF flag if no value found + } + indata.close(); + G4cout << "End-of-file reached.." << seedVector->size()<GetNewIntValue(newValue); + musrEventAction::nHowOftenToPrintEvent=n; + } + if ( command == RndmEventToSaveSeedsCmd ) + { + G4int n = RndmEventToSaveSeedsCmd->GetNewIntValue(newValue); + musrPrimaryGeneratorAction::nRndmEventToSaveSeeds=n; + } + +} diff --git a/src/musrErrorMessage.cc b/src/musrErrorMessage.cc new file mode 100644 index 0000000..87c5aac --- /dev/null +++ b/src/musrErrorMessage.cc @@ -0,0 +1,62 @@ +#include "musrErrorMessage.hh" + +musrErrorMessage::musrErrorMessage():nErrors(1) +{ + pointerToErrors=this; + severityWord[INFO]="INFO"; + severityWord[WARNING]="WARNING"; + severityWord[SERIOUS]="SERIOUS"; + severityWord[FATAL]="FATAL"; +} + +musrErrorMessage::~musrErrorMessage() {} + +musrErrorMessage* musrErrorMessage::pointerToErrors=NULL; +musrErrorMessage* musrErrorMessage::GetInstance() { + return pointerToErrors; +} + +void musrErrorMessage::musrError(SEVERITY severity, G4String message, G4bool silent) { + std::map::iterator it; + it = ErrorMapping.find(message); + if (it == ErrorMapping.end()) { // The error message is called for the first time + ErrorStruct actualErrorMessage; + actualErrorMessage.mesSeverity = severity; + actualErrorMessage.nTimes = 1; + ErrorMapping[message]=actualErrorMessage; + G4cout<<"!!!"<1) { + G4cout<<"!!!"<::iterator it; + G4cout<<"------ ERROR SUMMARY: ----------------------------------------------------------------"<GetEventID()); + + // if (thisEventNr == 44654) {trackingManager->SetVerboseLevel(2);} + musrSteppingAction::GetInstance()->DoAtTheBeginningOfEvent(); + + if (F04GlobalField::Exists()) { + F04GlobalField::getObject() -> CheckWhetherAnyNominalFieldValueNeedsToBeChanged(thisEventNr); + } +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrEventAction::EndOfEventAction(const G4Event* evt) { + // cout << ":." << flush; + long thisEventNr = (long) evt->GetEventID(); + + // get number of stored trajectories + G4TrajectoryContainer* trajectoryContainer = evt->GetTrajectoryContainer(); + G4int n_trajectories = 0; + if (trajectoryContainer) n_trajectories = trajectoryContainer->entries(); + + // G4cout << ">>> Event " << evt->GetEventID() << G4endl; + + // periodic printing + // + // if (thisEventNr != 0 and thisEventNr%10000 == 0) { + if (thisEventNr == 0) timeOfRunStart=time(0); + if ((time(0)-timeOfRunStart)>maximumRunTimeAllowed) { + // Stop the execution of the run - the run took already too long time + char eMessage[200]; + sprintf(eMessage,"musrEventAction::EndOfEventAction(): Run execution exceeded the allowed maximum time (maximum = %f sec) ==> RUN STOPPED",maximumRunTimeAllowed); + musrErrorMessage::GetInstance()->musrError(WARNING,eMessage,false); + G4RunManager* fRunManager = G4RunManager::GetRunManager(); + fRunManager->AbortRun(true); + } + if (thisEventNr != 0 and thisEventNr%nHowOftenToPrintEvent == 0) { + time_t curr=time(0); + //char * ctime(const time_t * tp); + G4cout << ">>> Event " << evt->GetEventID() <<". Running already for "<GetTrajectoryContainer()))[i]); + trj->DrawTrajectory(1000); + } + } +} diff --git a/src/musrMuFormation.cc b/src/musrMuFormation.cc new file mode 100644 index 0000000..c230389 --- /dev/null +++ b/src/musrMuFormation.cc @@ -0,0 +1,111 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +// Muonium Formation according to yield.cc function (through GetYields method). +// Id : musrMuFormation.cc, v 1.4 +// Author: Taofiq PARAISO, T. Shiroka +// Date : 2007-12 +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + +#include "musrMuFormation.hh" + +using namespace std; + +musrMuFormation::musrMuFormation(const G4String& name, G4ProcessType aType) + : G4VDiscreteProcess(name, aType){} + +musrMuFormation::~musrMuFormation(){} + +G4VParticleChange* musrMuFormation::PostStepDoIt(const G4Track& trackData, + const G4Step& aStep) +{ // Initialize ParticleChange (by setting all its members equal to + // the corresponding members in G4Track) + fParticleChange.Initialize(trackData); + + G4Track theNewTrack; + if(CheckCondition(aStep)) + { + GetDatas(&aStep); + G4Step theStep; + PrepareSecondary( trackData); + + fParticleChange.AddSecondary(aSecondary); + fParticleChange.ProposeTrackStatus(fStopAndKill) ; + } + else + { + fParticleChange.ProposeTrackStatus(trackData.GetTrackStatus()) ; + } + return &fParticleChange; +} + + +G4bool musrMuFormation::CheckCondition(const G4Step& aStep) +{ // Decide when to call the MuFormation process - i.e. for muons going through the C foil. + G4bool condition=false; + p_name = aStep.GetTrack()->GetDefinition()->GetParticleName(); // particle name + //if(p_name == "mu+"&&aStep.GetTrack()->GetVolume()->GetLogicalVolume()->GetName()=="log_CFoil") + std::string logVolName = aStep.GetTrack()->GetVolume()->GetLogicalVolume()->GetName(); + if(p_name == "mu+" && ((logVolName=="log_coulombCFoil")||(logVolName=="log_CFoil"))) + { + condition=true; + } + return condition; +} + + +G4double musrMuFormation::GetMeanFreePath(const G4Track&, + G4double, + G4ForceCondition* condition) +{ + *condition = Forced; + return DBL_MAX; +} + + +void musrMuFormation::GetDatas(const G4Step* aStep) +{ // Particle generation according to yield table + particleTable=G4ParticleTable::GetParticleTable(); + rnd=G4UniformRand(); + G4double E = aStep->GetTrack()->GetDynamicParticle()->GetKineticEnergy()/keV; + Gonin.GetYields(E,105.658369*1000,yvector); // Energy [keV], muon mass [keV/c2], yield table + G4String p_new = "Mu"; + + // Positive muon + if(p_name=="mu+") + { + if(rndFindParticle(p_name) ; + } + else + { + particle = particleTable->FindParticle(p_new); + } + + // Set the new dynamic particle DP + DP = new G4DynamicParticle(particle, + aStep->GetTrack()->GetDynamicParticle()->GetMomentumDirection(), + aStep->GetTrack()->GetDynamicParticle()->GetKineticEnergy()); + + // IMPORTANT : COPY THOSE DATA TO GET THE SAME PARTICLE PROPERTIES!!! + // SHOULD BE KEPT WHEN BUILDING A PARTICLE CHANGE + DP->SetProperTime( aStep->GetTrack()->GetDynamicParticle()->GetProperTime()); + DP->SetPolarization(aStep->GetTrack()->GetDynamicParticle()->GetPolarization().x(), + aStep->GetTrack()->GetDynamicParticle()->GetPolarization().y(), + aStep->GetTrack()->GetDynamicParticle()->GetPolarization().z()); + DP->SetPreAssignedDecayProperTime(aStep->GetTrack()->GetDynamicParticle()->GetPreAssignedDecayProperTime()); + } +} + + +void musrMuFormation::PrepareSecondary(const G4Track& track) +{ + if(p_name=="mu+") + { + aSecondary = new G4Track(DP,track.GetGlobalTime(),track.GetPosition()); + } +} diff --git a/src/musrMuScatter.cc b/src/musrMuScatter.cc new file mode 100644 index 0000000..6ffcc28 --- /dev/null +++ b/src/musrMuScatter.cc @@ -0,0 +1,86 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +// Muonium "Scattering" +// Id : musrMuScatter.cc, v 1.4 +// Author: Taofiq PARAISO, T. Shiroka +// Date : 2007-12 +// Notes : Simplified model for Mu scattering. Spin effects have been excluded. +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + +#include "musrMuScatter.hh" + +using namespace std; + +musrMuScatter::musrMuScatter(const G4String& name, + G4ProcessType aType) + : G4VDiscreteProcess(name, aType){} + +musrMuScatter:: ~musrMuScatter(){} + +/*! - At the end of the step, the current volume is checked and if Muonium is in a solid + material (except for the carbon foil where it is generated), it is stopped immediately. */ +G4VParticleChange* musrMuScatter::PostStepDoIt(const G4Track& trackData, + const G4Step& aStep) +{ + fParticleChange.Initialize(trackData); + + //! Tao - Get time information */ + itime = trackData.GetProperTime(); + gtime = trackData.GetGlobalTime(); + ftime = trackData.GetDynamicParticle()->GetPreAssignedDecayProperTime(); + + deltatime = ftime - itime; + fParticleChange.ProposeGlobalTime(deltatime + itime -gtime); + + /*! - Set position, momentum, energy and time of the particle change. */ + fParticleChange.ProposePosition(trackData.GetPosition()); + fParticleChange.ProposeMomentumDirection(trackData.GetMomentumDirection()); + fParticleChange.ProposeEnergy(trackData.GetKineticEnergy()); + fParticleChange.ProposeGlobalTime(gtime); + fParticleChange.ProposeProperTime(itime); + fParticleChange.ProposeTrackStatus(trackData.GetTrackStatus()) ; + + /*! - Verify the condition of applying the process: if Mu is in a material + different than vacuum and carbon foil, then stop it directly. */ + if( CheckCondition(aStep)) + { + fParticleChange.ProposePosition(trackData.GetStep()->GetPreStepPoint()->GetPosition()); + fParticleChange.ProposeTrackStatus(fStopButAlive) ; + } + + /*! - Return the changed particle object. */ + return &fParticleChange; +} + + +/*! - Muonium will be stopped as soon as it enters a material different than vacuum or C foil. */ +G4bool musrMuScatter::CheckCondition(const G4Step& aStep) +{ + G4bool condition = false; + p_name = aStep.GetTrack()->GetDefinition()->GetParticleName(); // particle name + if(p_name == "Mu" && aStep.GetTrack()->GetVolume()->GetLogicalVolume()->GetName()!="log_CFoil" && + aStep.GetTrack()->GetVolume()->GetLogicalVolume()->GetMaterial()->GetName()!="G4_Galactic") + { + condition=true; + } + return condition; +} + + +G4double musrMuScatter::GetMeanFreePath(const G4Track&, + G4double, + G4ForceCondition* condition) +{ + *condition = Forced; + return DBL_MAX; +} + + +void musrMuScatter::PrepareSecondary(const G4Track& track) +{ + aSecondary = new G4Track(DP,track.GetDynamicParticle()->GetPreAssignedDecayProperTime(),track.GetPosition()); +} diff --git a/src/musrMuonium.cc b/src/musrMuonium.cc new file mode 100644 index 0000000..37cc0ea --- /dev/null +++ b/src/musrMuonium.cc @@ -0,0 +1,112 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +// +// ******************************************************************** +// * License and Disclaimer * +// * * +// * The Geant4 software is copyright of the Copyright Holders of * +// * the Geant4 Collaboration. It is provided under the terms and * +// * conditions of the Geant4 Software License, included in the file * +// * LICENSE and available at http://cern.ch/geant4/license . These * +// * include a list of copyright holders. * +// * * +// * Neither the authors of this software system, nor their employing * +// * institutes,nor the agencies providing financial support for this * +// * work make any representation or warranty, express or implied, * +// * regarding this software system or assume any liability for its * +// * use. Please see the license in the file LICENSE and URL above * +// * for the full disclaimer and the limitation of liability. * +// * * +// * This code implementation is the result of the scientific and * +// * technical work of the GEANT4 collaboration. * +// * By using, copying, modifying or distributing the software (or * +// * any work based on the software) you agree to acknowledge its * +// * use in resulting scientific publications, and indicate your * +// * acceptance of all terms of the Geant4 Software license. * +// ******************************************************************** +// +// +// $Id: musrMuonium.cc,v 1.13 2007/03/15 06:53:58 kurasige Exp $ +// GEANT4 tag $Name: geant4-09-00 $ +// +// +// ---------------------------------------------------------------------- +// GEANT 4 class implementation file +// +// History: first implementation, based on object model of +// 4th April 1996, G. Cosmo +// ********************************************************************** +// New implementation as an utility class M. Asai, 26 July 2004 +// ---------------------------------------------------------------------- + +#include "musrMuonium.hh" +#include "G4ParticleTable.hh" + +#include "MuDecayChannel.hh" +#include "G4DecayTable.hh" + +// ###################################################################### +// ### MUONIUM ### +// ###################################################################### +musrMuonium* musrMuonium::theInstance = 0; + +musrMuonium* musrMuonium::Definition() +{ + if (theInstance !=0) return theInstance; + const G4String name = "Mu"; + // search in particle table] + G4ParticleTable* pTable = G4ParticleTable::GetParticleTable(); + G4ParticleDefinition* anInstance = pTable->FindParticle(name); + if (anInstance ==0) + { + // create particle + // + // Arguments for constructor are as follows + // name mass width charge + // 2*spin parity C-conjugation + // 2*Isospin 2*Isospin3 G-parity + // type lepton number baryon number PDG encoding + // stable lifetime decay table + // shortlived subType anti_encoding + anInstance = new G4ParticleDefinition( + name, 0.1056584*GeV, 2.99591e-16*MeV, 0.*eplus, + 1, 0, 0, + 0, 0, 0, + "lepton", -1, 0, -1313, + false, 2197.03*ns, NULL, + false, "mu" + ); + // Bohr magnetron of Muonium - T. Shiroka + // The magnetic moment of Mu is the sum of those of mu+ and e- with + // the respective gyromagnetic ratio anomalies as coefficients + + G4double muBmu = 0.5*eplus*hbar_Planck/(0.10565840*GeV/c_squared); + G4double muBel = -0.5*eplus*hbar_Planck/(0.51099906*MeV/c_squared); + G4double muB = 1.0011659208*muBmu + 1.0011596521859*muBel; + + anInstance->SetPDGMagneticMoment( muB ); + + //create Decay Table + G4DecayTable* table = new G4DecayTable(); + // create a decay channel + G4VDecayChannel* mode = new MuDecayChannel("Mu",1.00); + table->Insert(mode); + anInstance->SetDecayTable(table); + } + theInstance = reinterpret_cast(anInstance); + return theInstance; +} + +musrMuonium* musrMuonium::MuoniumDefinition() +{ + return Definition(); +} + +musrMuonium* musrMuonium::Muonium() +{ + return Definition(); +} + diff --git a/src/musrParameters.cc b/src/musrParameters.cc new file mode 100644 index 0000000..755a3a4 --- /dev/null +++ b/src/musrParameters.cc @@ -0,0 +1,91 @@ +#include "musrParameters.hh" +// #include "musrErrorMessage.hh" - musrErrorMessage class can not be used inside "musrParameters" constructor, because +// musrErrorMessage is crated later! + +musrParameters::musrParameters(G4String steeringFileName) +{ + pointerToParameters = this; + boolG4RegionRequested = false; + mySteeringFileName = steeringFileName; + + // Read in the parameters, which have to be known before the detector construction is run + // (and therefore the parameters can not be read in in the musrDetectorConstruction.cc class). + + FILE *fSteeringFile=fopen(steeringFileName.c_str(),"r"); + if (fSteeringFile==NULL) { + G4cout<<"musrParameters::musrParameters: steeringFileName=\""< Insert(new musrMuonDecayChannel("mu+",1.00)); + // G4MuonPlus::MuonPlusDefinition() -> SetDecayTable(MuonPlusDecayTable); + //csk + // + // Muonium - TS + musrMuonium::MuoniumDefinition(); + // + // nu_e + G4NeutrinoE::NeutrinoEDefinition(); + G4AntiNeutrinoE::AntiNeutrinoEDefinition(); + // nu_mu + G4NeutrinoMu::NeutrinoMuDefinition(); + G4AntiNeutrinoMu::AntiNeutrinoMuDefinition(); + + //cks: Trial to use Geant4 muon decay with spin + G4DecayTable* MuonPlusDecayTable = new G4DecayTable(); + MuonPlusDecayTable -> Insert(new G4MuonDecayChannelWithSpin("mu+",1.00)); + // MuonPlusDecayTable -> Insert(new G4MuonDecayChannelWithSpin("mu+",0.986)); + // MuonPlusDecayTable -> Insert(new G4MuonRadiativeDecayChannelWithSpin("mu+",0.014)); + G4MuonPlus::MuonPlusDefinition() -> SetDecayTable(MuonPlusDecayTable); + // + // G4DecayTable* MuonMinusDecayTable = new G4DecayTable(); + // MuonMinusDecayTable -> Insert(new G4MuonDecayChannelWithSpin("mu-",1.00)); + // G4MuonMinus::MuonMinusDefinition() -> SetDecayTable(MuonMinusDecayTable); + //csk + // + //TS: Using the muonium decay with and without spin + G4DecayTable* MuoniumDecayTable = new G4DecayTable(); + MuoniumDecayTable -> Insert(new MuDecayChannel("Mu",0.50)); + MuoniumDecayTable -> Insert(new MuDecayChannelWithSpin("Mu",0.5)); + musrMuonium::MuoniumDefinition() -> SetDecayTable(MuoniumDecayTable); + //MuoniumDecayTable ->DumpInfo(); // Info on muonium decay channels +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrPhysicsList::ConstructMesons() +{ + // mesons + // light mesons + G4PionPlus::PionPlusDefinition(); + G4PionMinus::PionMinusDefinition(); + G4PionZero::PionZeroDefinition(); + G4Eta::EtaDefinition(); + G4EtaPrime::EtaPrimeDefinition(); + G4KaonPlus::KaonPlusDefinition(); + G4KaonMinus::KaonMinusDefinition(); + G4KaonZero::KaonZeroDefinition(); + G4AntiKaonZero::AntiKaonZeroDefinition(); + G4KaonZeroLong::KaonZeroLongDefinition(); + G4KaonZeroShort::KaonZeroShortDefinition(); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrPhysicsList::ConstructBaryons() +{ + // baryons + G4Proton::ProtonDefinition(); + G4AntiProton::AntiProtonDefinition(); + + G4Neutron::NeutronDefinition(); + G4AntiNeutron::AntiNeutronDefinition(); + + // ions + G4IonConstructor iConstructor; + iConstructor.ConstructParticle(); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrPhysicsList::ConstructProcess() +{ + AddTransportation(); + ConstructEM(); + ConstructGeneral(); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +#include "G4ComptonScattering.hh" +#include "G4GammaConversion.hh" +#include "G4PhotoElectricEffect.hh" + +#include "G4MultipleScattering.hh" + +#include "G4eIonisation.hh" +#include "G4eBremsstrahlung.hh" +#include "G4eplusAnnihilation.hh" + +#include "G4MuIonisation.hh" +#include "G4MuBremsstrahlung.hh" +#include "G4MuPairProduction.hh" + +#include "G4hIonisation.hh" + +#include "G4UserSpecialCuts.hh" + +//#include "musrAtRestSpinRotation.hh" + +// For low energy physics processes: +#include "G4LowEnergyCompton.hh" +//#include "G4LowEnergyPolarizedCompton.hh" +#include "G4LowEnergyGammaConversion.hh" +#include "G4LowEnergyPhotoElectric.hh" +#include "G4LowEnergyRayleigh.hh" +#include "G4LowEnergyBremsstrahlung.hh" +#include "G4LowEnergyIonisation.hh" +#include "G4hLowEnergyIonisation.hh" + + +// For Penelope processes: +#include "G4PenelopeCompton.hh" +#include "G4PenelopeGammaConversion.hh" +#include "G4PenelopePhotoElectric.hh" +#include "G4PenelopeRayleigh.hh" +#include "G4PenelopeIonisation.hh" +#include "G4PenelopeBremsstrahlung.hh" +#include "G4PenelopeAnnihilation.hh" + +// For Coulomb scattering instead of multiple scattering +#include "G4CoulombScattering.hh" +#include "G4CoulombScatteringModel.hh" + +// For Muonium formation in the Carbon foil +#include "musrMuFormation.hh" // includes the yield function Y = Y(E). + +// For a simple Muonium "scattering" when Mu hits solid materials +#include "musrMuScatter.hh" + + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrPhysicsList::ConstructEM() +{ + // cks 2008.08.22. - Adding the possibility to define the processes from the steering file: + char charSteeringFileName[1000]; strcpy(charSteeringFileName,(musrParameters::mySteeringFileName).c_str()); + FILE *fSteeringFile=fopen(charSteeringFileName,"r"); + if (fSteeringFile==NULL) { + sprintf(eMessage,"musrPhysicsList::ConstructEM(): Failed to open macro file \"%s\" .",charSteeringFileName); + musrErrorMessage::GetInstance()->musrError(FATAL,eMessage,false); + } + else {G4cout<<"musrPhysicsList: The Physics processes are being defined:"< FindParticle(stringParticleName); + // G4cout<<"particleDefinition of "<musrError(FATAL,eMessage,false); + } + G4ProcessManager* pManager = particleDefinition->GetProcessManager(); + + if (strcmp(tmpString2,"addDiscreteProcess")==0) { + if (stringProcessName=="G4PhotoElectricEffect") pManager->AddDiscreteProcess(new G4PhotoElectricEffect); + else if (stringProcessName=="G4ComptonScattering") pManager->AddDiscreteProcess(new G4ComptonScattering); + else if (stringProcessName=="G4GammaConversion") pManager->AddDiscreteProcess(new G4GammaConversion); + else if (stringProcessName=="G4PenelopePhotoElectric") pManager->AddDiscreteProcess(new G4PenelopePhotoElectric); + else if (stringProcessName=="G4PenelopeCompton") pManager->AddDiscreteProcess(new G4PenelopeCompton); + else if (stringProcessName=="G4PenelopeGammaConversion") pManager->AddDiscreteProcess(new G4PenelopeGammaConversion); + else if (stringProcessName=="G4PenelopeRayleigh") pManager->AddDiscreteProcess(new G4PenelopeRayleigh); + else if (stringProcessName=="G4LowEnergyPhotoElectric") pManager->AddDiscreteProcess(new G4LowEnergyPhotoElectric); + else if (stringProcessName=="G4LowEnergyCompton") pManager->AddDiscreteProcess(new G4LowEnergyCompton); + else if (stringProcessName=="G4LowEnergyGammaConversion") pManager->AddDiscreteProcess(new G4LowEnergyGammaConversion); + else if (stringProcessName=="G4LowEnergyRayleigh") pManager->AddDiscreteProcess(new G4LowEnergyRayleigh); + + else if (stringProcessName=="G4CoulombScattering") pManager->AddDiscreteProcess(new G4CoulombScattering); + else { + sprintf(eMessage,"musrPhysicsList: Process \"%s\" is not implemented in musrPhysicsList.cc for addDiscreteProcess. It can be easily added.", + charProcessName); + musrErrorMessage::GetInstance()->musrError(FATAL,eMessage,false); + } + } + else if (strcmp(tmpString2,"addProcess")==0) { + G4int nr1, nr2, nr3; + char charRegion1[100]="", charRegion2[100]="", charRegion3[100]="", charControlString[10]=""; + sscanf(&line[0],"%*s %*s %*s %*s %*s %d %d %d %s %s %s %s",&nr1,&nr2,&nr3,charRegion1,charRegion2,charRegion3,charControlString); + if (stringProcessName=="G4MultipleScattering") pManager->AddProcess(new G4MultipleScattering,nr1,nr2,nr3); + else if (stringProcessName=="G4eIonisation") pManager->AddProcess(new G4eIonisation,nr1,nr2,nr3); + else if (stringProcessName=="G4eBremsstrahlung") pManager->AddProcess(new G4eBremsstrahlung,nr1,nr2,nr3); + else if (stringProcessName=="G4eplusAnnihilation") pManager->AddProcess(new G4eplusAnnihilation,nr1,nr2,nr3); + else if (stringProcessName=="G4PenelopeIonisation") pManager->AddProcess(new G4PenelopeIonisation,nr1,nr2,nr3); + else if (stringProcessName=="G4PenelopeBremsstrahlung") pManager->AddProcess(new G4PenelopeBremsstrahlung,nr1,nr2,nr3); + else if (stringProcessName=="G4PenelopeAnnihilation") pManager->AddProcess(new G4PenelopeAnnihilation,nr1,nr2,nr3); + else if (stringProcessName=="G4LowEnergyIonisation") pManager->AddProcess(new G4LowEnergyIonisation,nr1,nr2,nr3); + else if (stringProcessName=="G4LowEnergyBremsstrahlung") pManager->AddProcess(new G4LowEnergyBremsstrahlung,nr1,nr2,nr3); + else if (stringProcessName=="G4MuIonisation") pManager->AddProcess(new G4MuIonisation,nr1,nr2,nr3); + else if (stringProcessName=="G4MuBremsstrahlung") pManager->AddProcess(new G4MuBremsstrahlung,nr1,nr2,nr3); + else if (stringProcessName=="G4MuPairProduction") pManager->AddProcess(new G4MuPairProduction,nr1,nr2,nr3); + // else if (stringProcessName=="G4DecayWithSpin") pManager->AddProcess(new G4DecayWithSpin,nr1,nr2,nr3); + // else if (stringProcessName=="G4hIonisation") pManager->AddProcess(new G4hIonisation,nr1,nr2,nr3); + // else if (stringProcessName=="G4hLowEnergyIonisation") pManager->AddProcess(new G4hLowEnergyIonisation,nr1,nr2,nr3); + else if (stringProcessName=="musrMuFormation") pManager->AddProcess(new musrMuFormation,nr1,nr2,nr3); + // cks: musrMuScatter could be uncommented here, but testing is needed, because Toni has some strange comments + // in his original "musrPhysicsList.cc about implementing musrMuScatter. + // else if (stringProcessName=="musrMuScatter") pManager->AddProcess(new musrMuScatter,nr1,nr2,nr3); + else if (stringProcessName=="MultipleAndCoulombScattering") { + G4MultipleScattering* multScat = new G4MultipleScattering(); + // G4CoulombScattering* coulScat = new G4CoulombScattering(); + G4CoulombScatteringModel* coulScatModel = new G4CoulombScatteringModel(); + if (strcmp(charRegion1,"")!=0) { + G4Region* regionForCoulomb = FindG4Region(charRegion1,line); + G4cout<<" Adding Coulomb scattering model to multiple scattering model for region "<AddEmModel(0,coulScatModel,regionForCoulomb); + // multScat->AddEmModel(0,multScat,regionForCoulomb); + } + if (strcmp(charRegion2,"")!=0) { + G4Region* regionForCoulomb = FindG4Region(charRegion2,line); + G4cout<<" Adding Coulomb scattering model to multiple scattering model for region "<AddEmModel(0,coulScatModel,regionForCoulomb); + } + if (strcmp(charRegion3,"")!=0) { + G4Region* regionForCoulomb = FindG4Region(charRegion3,line); + G4cout<<" Adding Coulomb scattering model to multiple scattering model for region "<AddEmModel(0,coulScatModel,regionForCoulomb); + } + if (strcmp(charControlString,"")!=0) { + G4cout<<"More than 3 regions requested for Coulomb Scattering, but presently only up to 3 such regions are supported."<AddProcess(multScat,nr1,nr2,nr3); + } + else { + sprintf(eMessage,"musrPhysicsList: Process \"%s\" is not implemented in musrPhysicsList.cc for addProcess. It can be easily added.", + charProcessName); + musrErrorMessage::GetInstance()->musrError(FATAL,eMessage,false); + } + } + } + + else ReportProblemWithProcessDefinition(line); + } + } + fclose(fSteeringFile); + + G4cout<<"\n\n\n\n"<GetMyTypeOfProcesses(); + //del G4cout<<"musrPhysicsList::ConstructEM(): myTypeOfProcesses="<reset(); + while( (*theParticleIterator)() ){ + G4ParticleDefinition* particle = theParticleIterator->value(); + G4ProcessManager* pmanager = particle->GetProcessManager(); + G4String particleName = particle->GetParticleName(); + + if ((particleName == "gamma")||(particleName == "e-")||(particleName == "e+")) { + // do nothing + } + + else if ((particleName=="mu+")||(particleName=="mu-")) { //muon + G4DecayWithSpin* theDecayProcess = new G4DecayWithSpin(); + // theDecayProcess->SetVerboseLevel(2); + pmanager->AddProcess(theDecayProcess); + pmanager ->SetProcessOrderingToLast(theDecayProcess, idxAtRest); + pmanager ->SetProcessOrdering(theDecayProcess, idxPostStep); + } + + else if (particleName=="Mu") { + // TS: + // Muonium "scattering" Kamil: the following 3 lines could be replaced by reading the musrMuScatter + // process through the steering file + G4VProcess* aMuScatt = new musrMuScatter(); + pmanager->AddProcess(aMuScatt); + pmanager->SetProcessOrdering(aMuScatt, idxPostStep, 1); + // + G4Decay* theDecayProcess = new G4Decay(); + //musrDecayWithSpin* theDecayProcess = new musrDecayWithSpin(); + pmanager->AddProcess(theDecayProcess); + pmanager->SetProcessOrderingToLast(theDecayProcess, idxAtRest); + pmanager->SetProcessOrdering(theDecayProcess, idxPostStep); + } + + + else if ((!particle->IsShortLived()) && + (particle->GetPDGCharge() != 0.0) && + (particle->GetParticleName() != "chargedgeantino")) { + //all others charged particles except geantino + pmanager->AddProcess(new G4MultipleScattering,-1, 1,1); + // if (myTypeOfProcesses=="highenergy") { + // pmanager->AddProcess(new G4hIonisation, -1, 2,2); + // } + // else { + pmanager->AddProcess(new G4hLowEnergyIonisation, -1, 2,2); + // } + ///pmanager->AddProcess(new G4UserSpecialCuts, -1,-1,3); + } + } +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + + + +#include "G4Decay.hh" +void musrPhysicsList::ConstructGeneral() { + if (musrParameters::boolG4GeneralParticleSource) { + G4RadioactiveDecay* theRadioactiveDecay = new G4RadioactiveDecay(); + G4GenericIon* ion = G4GenericIon::GenericIon(); + + theParticleIterator->reset(); + while( (*theParticleIterator)() ){ + G4ParticleDefinition* particle = theParticleIterator->value(); + G4ProcessManager* pmanager = particle->GetProcessManager(); + + if (particle == ion) { + pmanager->AddProcess(theRadioactiveDecay, 0, -1, 3); + } + } + } +} + + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +#include "G4Region.hh" +#include "G4RegionStore.hh" +#include "G4ProductionCuts.hh" + +void musrPhysicsList::SetCuts() +{ + //G4VUserPhysicsList::SetCutsWithDefault method sets + //the default cut value for all particle types + // + SetCutsWithDefault(); + + if (verboseLevel>0) DumpCutValuesTable(); + DumpCutValuesTable(); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrPhysicsList::ReportProblemWithProcessDefinition(char myString[501]) { + G4cout<<"\nE R R O R in musrPhysicsList.cc: " + <<"Unknown keyword requested in the steering (*.mac) file :"<GetRegion(regionName,false); + if( myRegion != NULL ) { // G4Region found + return myRegion; + } + else { // G4Region not found + G4cout<<"musrPhysicsList: G4Region "< +#include "musrRootOutput.hh" //cks for storing some info in the Root output file +#include "musrErrorMessage.hh" + + +G4bool musrPrimaryGeneratorAction::setRandomNrSeedAccordingEventNr=0; +G4bool musrPrimaryGeneratorAction::setRandomNrSeedFromFile=0; +G4bool musrPrimaryGeneratorAction::setRandomNrSeedFromFile_RNDM=0; +G4int musrPrimaryGeneratorAction::nRndmEventToSaveSeeds=-2; + +std::vector * musrPrimaryGeneratorAction::pointerToSeedVector=NULL; +std::vector * musrPrimaryGeneratorAction::GetPointerToSeedVector() { + return pointerToSeedVector; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... + +musrPrimaryGeneratorAction::musrPrimaryGeneratorAction( + musrDetectorConstruction* musrDC) + :musrDetector(musrDC), x0(0), y0(0), z0(-10*cm), xSigma(0), ySigma(0), zSigma(0), + rMaxAllowed(1e10*mm), zMinAllowed(-1e10*mm), zMaxAllowed(1e10*mm), + p0(0), pSigma(0), pMinAllowed(0), pMaxAllowed(1e10*mm), + xangle0(0), yangle0(0), xangleSigma(0), yangleSigma(0), pitch(0), + UnpolarisedMuonBeam(false), TransversalyUnpolarisedMuonBeam(false), xPolarisIni(1.), yPolarisIni(0.), zPolarisIni(0.), + polarisFraction(1.), + muonDecayTimeMin(-1), muonDecayTimeMax(-1), muonMeanLife(2197.03*ns), + takeMuonsFromTurtleFile(false), z0_InitialTurtle(0), + numberOfGeneratedEvents(0), + turtleMomentumBite(false), turtleMomentumP0(0.), turtleSmearingFactor(0.) + //, firstCall(true) +{ + //create a messenger for this class + gunMessenger = new musrPrimaryGeneratorMessenger(this); + + // create a vector for storing the event numbers as seeds for the random number generator + pointerToSeedVector = new std::vector; + + // default particle kinematic + G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable(); + G4ParticleDefinition* muonParticle= particleTable->FindParticle("mu+"); + // cks Implement also alpha and proton particles for the simulation of Juan Pablo Urrego + alphaParticle= particleTable->FindParticle("alpha"); + protonParticle= particleTable->FindParticle("proton"); + // csk + + G4int n_particle = 1; + if (musrParameters::boolG4GeneralParticleSource) { + G4cout<<"musrPrimaryGeneratorAction: G4GeneralParticleSource is going to be initialised"<SetParticleDefinition(muonParticle); + } +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... + +musrPrimaryGeneratorAction::~musrPrimaryGeneratorAction() +{ + if (musrParameters::boolG4GeneralParticleSource) {delete particleSource;} + else {delete particleGun;} + delete gunMessenger; + if (takeMuonsFromTurtleFile) {fclose(fTurtleFile);} + G4cout<<"musrPrimaryGeneratorAction: Number of Generated Events = "<ClearAllRootVariables(); // Note that musrPrimaryGeneratorAction::GeneratePrimaries + // is called before the musrEventAction::BeginOfEventAction. + // Therefore "ClearAllRootVariables" is called already here + // (before the "SetInitialMuonParameters". + + // Set or read the seeds of random number generator + boolPrintInfoAboutGeneratedParticles=false; + SetOrReadTheRandomNumberSeeds(anEvent->GetEventID()); + + // If radioactive source is used, use G4GeneralParticleSource : + if (musrParameters::boolG4GeneralParticleSource) { + particleSource->GeneratePrimaryVertex(anEvent); + return; + } + + G4double x, y, z; + G4double p; + G4double xangle, yangle; + + if (takeMuonsFromTurtleFile) { + char line[501]; + G4int checkNrOfCounts=0; + do { + float xTmp, yTmp, xAngleTmp, yAngleTmp, pTmp; + float dummy1, dummy2; + int Ztmp=-1, Atmp=-1; + fgets(line,500,fTurtleFile); + if (feof(fTurtleFile)) { + rewind(fTurtleFile); + G4cout<<"End of TurtleFile, lets start from the beginning (numberOfGeneratedEvents = "<SetParticleDefinition(protonParticle);}// G4cout<<"proton"<SetParticleDefinition(alphaParticle);}// G4cout<<"alpha particle"<1000) { + G4cout<<"musrPrimaryGeneratorAction::GeneratePrimaries: Too strict requirements on the r position!"<(rMaxAllowed*rMaxAllowed) ); + z=z0; + // G4cout<<"x,y,z=("<(rMaxAllowed*rMaxAllowed))||(z>zMaxAllowed)||(z0) {p = G4RandGauss::shoot(p0,pSigma);} + else {p=p0;} + checkNrOfCounts++; + if (checkNrOfCounts>1000) { + G4cout<<"musrPrimaryGeneratorAction::GeneratePrimaries: Too strict requirements on the momentum!"<pMaxAllowed)||(p0) { xangle = G4RandGauss::shoot(xangle0,xangleSigma); } + else { xangle = xangle0; } + // Add the beam tilt, which depends on the distance from the beam centre. + // if (xSigma>0) {xangle += - pitch * (x-x0)/xSigma; } + if (pitch!=0) {xangle += - pitch * (x-x0); } + + if (yangleSigma>0) { yangle = G4RandGauss::shoot(yangle0,yangleSigma); } + else { yangle = yangle0; } + // Add the beam tilt, which depends on the distance from the beam centre. + // if (ySigma>0) {yangle += - pitch * (y-y0)/ySigma; } + if (pitch!=0) {yangle += - pitch * (y-y0); } + + } // end of the part specific for the muons generated by random rather then from TURTLE + + + // Calculate the final momentum + G4double px, py, pz; + px = p*sin(xangle); + py = p*sin(yangle); + pz = std::sqrt(p*p - px*px - py*py); + + + // Assign spin + G4double xpolaris=0, ypolaris=0, zpolaris=0; + if (UnpolarisedMuonBeam) { + // for genarating random numbers on the sphere see http://mathworld.wolfram.com/SpherePointPicking.html + G4double thetaTMP=pi/2; + if(!TransversalyUnpolarisedMuonBeam) thetaTMP = acos(2. * G4UniformRand()-1); + G4double phiTMP = 2. * pi * G4UniformRand(); + + xpolaris = std::sin(thetaTMP) * std::cos(phiTMP);; + ypolaris = std::sin(thetaTMP) * std::sin(phiTMP); + zpolaris = std::cos(thetaTMP); + } + else { + if (G4UniformRand()>((1.-polarisFraction)/2.)) { + xpolaris = xPolarisIni; ypolaris = yPolarisIni; zpolaris = zPolarisIni; + // G4cout<<"spin up"<SetParticlePosition(G4ThreeVector(x,y,z)); + G4double particle_mass = particleGun->GetParticleDefinition()->GetPDGMass(); + G4double particleEnergy = std::sqrt(p*p+particle_mass*particle_mass)-particle_mass; + particleGun->SetParticleEnergy(particleEnergy); + particleGun->SetParticleMomentumDirection(G4ThreeVector(px,py,pz)); + particleGun->SetParticlePolarization(G4ThreeVector(xpolaris,ypolaris,zpolaris)); + particleGun->GeneratePrimaryVertex(anEvent); + + // G4cout<<"musrPrimaryGeneratorAction: Parameters:"<0.) { + // G4cout<<"muonDecayTimeMin="<GetPrimaryVertex(0)->GetPrimary(0); + // G4double decayLowerLimit = 1-exp(-muonDecayTimeMin/muonMeanLife); + // G4double decayUpperLimit = 1-exp(-muonDecayTimeMax/muonMeanLife); + // G4double randomVal = G4UniformRand()*(decayUpperLimit-decayLowerLimit) + decayLowerLimit; + // G4double decaytime = -muonMeanLife*log(1-randomVal); + // + // The following code is numerically more stable compared to the commented lines above: + G4double expMin = exp(-muonDecayTimeMin/muonMeanLife); + G4double expMax = exp(-muonDecayTimeMax/muonMeanLife); + G4double decaytime = -muonMeanLife * log(G4UniformRand()*(expMax-expMin)+expMin); + // G4cout<<"decaytime="<SetProperTime(decaytime); + } + + // Save variables into ROOT output file: + myRootOutput->SetInitialMuonParameters(x,y,z,px,py,pz,xpolaris,ypolaris,zpolaris); + myRootOutput->StoreGeantParameter(7,float(numberOfGeneratedEvents)); + if (boolPrintInfoAboutGeneratedParticles) { + G4cout<<"musrPrimaryGeneratorAction::GeneratePrimaries: x="<0.0000000075)) { + G4cout<< "Transversaly unpolarised initial muons"<StoreGeantParameter(2,muonDecayTimeMin/microsecond); + myRootOutput->StoreGeantParameter(3,muonDecayTimeMax/microsecond); + myRootOutput->StoreGeantParameter(4,muonMeanLife/microsecond); +} + +//=============================================================================== +void musrPrimaryGeneratorAction::SetTurtleInput(G4String turtleFileName) { + takeMuonsFromTurtleFile = true; + fTurtleFile = fopen(turtleFileName.c_str(),"r"); + if (fTurtleFile==NULL) { + G4cout << "E R R O R : Failed to open TURTLE input file \"" << turtleFileName + <<"\"."<< G4endl; + G4cout << "S T O P F O R C E D" << G4endl; + exit(1); + } + else {G4cout << "Turtle input file \"" << turtleFileName <<"\" opened."<< G4endl;} +} + +//=============================================================================== +void musrPrimaryGeneratorAction::SetTurtleInputFileToEventNo(G4int lineNumberOfTurtleFile) { + if (fTurtleFile==NULL) { + G4cout << "musrPrimaryGeneratorAction::SetTurtleInputFileToEventNo:" + <<" TURTLE input file not found - line number can not be set."<rndmSaveThisEvent(); + boolPrintInfoAboutGeneratedParticles = true; + } + if (eventID == 0) { + if (setRandomNrSeedFromFile_RNDM) { + G4cout<<"musrPrimaryGeneratorAction::SetOrReadTheRandomNumberSeeds: Restoring random number seeds from file kamil.rndm"<RestoreRandomNumberStatus("kamil.rndm"); + boolPrintInfoAboutGeneratedParticles = true; + } + } + if (setRandomNrSeedFromFile) { + // G4cout<<"RandomNrInitialisers.size()="<size()<size())) { + G4cout <<"musrEventAction.cc: seed will be set to="<< pointerToSeedVector->at(eventID)<at(eventID)); + CLHEP::RandGauss::setFlag(false); + boolPrintInfoAboutGeneratedParticles = true; + } + } + else if (setRandomNrSeedAccordingEventNr) { + // long seeds[2]; + // seeds[0] = (long) 234567890+thisEventNr*117; + // seeds[1] = (long) 333222111+thisEventNr*173; + // + // // seeds[1] = (long) (evt->GetEventID()); + // // seeds[0] = (long) 123456789; // This leads to a gap in the decay time histogram fro N=100000 events + // // seeds[1] = (long) 333222111+thisEventNr; // ----------------------------||------------------------------------ + // thisEventNr++; + // CLHEP::HepRandom::setTheSeeds(seeds); + // // G4cout << "seed1: " << seeds[0] << "; seed2: " << seeds[1] << G4endl; + // + // G4cout <<" thisEventNr="<GetPDGMass(); + p0=std::sqrt(val*val + 2*mu_mass*val); + // G4cout<<"musrPrimaryGeneratorAction::SetKEnergy: Muon kinetic energy of " + // < initial muon momentum set to "<SetGuidance(" Set x0, y0, z0 of the generated muons (with unit)"); + setvertexCmd->SetParameterName("mes_x0","mes_y0","mes_z0",true,true); + setvertexCmd->SetDefaultUnit("mm"); + + setvertexSigmaCmd = new G4UIcmdWith3VectorAndUnit("/gun/vertexsigma",this); + setvertexSigmaCmd->SetGuidance(" Set xSigma, ySigma, ySigma of the generated muons (with unit)"); + setvertexSigmaCmd->SetParameterName("mes_xSigma","mes_ySigma","mes_zSigma",true,true); + setvertexSigmaCmd->SetDefaultUnit("mm"); + + setvertexBoundaryCmd = new G4UIcmdWith3VectorAndUnit("/gun/vertexboundary",this); + setvertexBoundaryCmd->SetGuidance(" Set maximum allowed radius, zmin, zmax of the generated vertex (with unit)"); + setvertexBoundaryCmd->SetParameterName("mes_rMaxAllowed","mes_zMinAllowed","mes_zMaxAllowed",true,true); + setvertexBoundaryCmd->SetDefaultUnit("mm"); + + setKEnergyCmd = new G4UIcmdWithADoubleAndUnit("/gun/kenergy",this); + setKEnergyCmd->SetGuidance(" Set kinetic energy of the generated muons (with unit)"); + setKEnergyCmd->SetParameterName("mes_E0",true); + setKEnergyCmd->SetDefaultUnit("MeV"); + + setMomentumCmd = new G4UIcmdWithADoubleAndUnit("/gun/momentum",this); + setMomentumCmd->SetGuidance(" Set mean momentum of the generated muons (with unit)"); + setMomentumCmd->SetParameterName("mes_p0",true); + setMomentumCmd->SetDefaultUnit("MeV"); + + setMomentumSmearingCmd = new G4UIcmdWithADoubleAndUnit("/gun/momentumsmearing",this); + setMomentumSmearingCmd->SetGuidance(" Set sigma of the momentum of the generated muons (with unit)"); + setMomentumSmearingCmd->SetParameterName("mes_pSigma",true); + setMomentumSmearingCmd->SetDefaultUnit("MeV"); + + setMomentumBoundaryCmd = new G4UIcmdWith3VectorAndUnit("/gun/momentumboundary",this); + setMomentumBoundaryCmd->SetGuidance(" Set minimum and maximum momentum allowed (with unit, z component ignored)"); + setMomentumBoundaryCmd->SetParameterName("mes_pMinAllowed","mes_pMaxAllowed","mes_dummy",true,true); + setMomentumBoundaryCmd->SetDefaultUnit("MeV"); + + setTiltAngleCmd = new G4UIcmdWith3VectorAndUnit("/gun/tilt",this); + setTiltAngleCmd->SetGuidance(" Set tilt angle of the generated muons (with unit, z component ignored)"); + setTiltAngleCmd->SetParameterName("mes_xangle","mes_yangle","dummy",true,true); + setTiltAngleCmd->SetDefaultUnit("deg"); + + setSigmaTiltAngleCmd = new G4UIcmdWith3VectorAndUnit("/gun/tiltsigma",this); + setSigmaTiltAngleCmd->SetGuidance(" Set sigma of the tilt angle (with unit, z component ignored)"); + setSigmaTiltAngleCmd->SetParameterName("mes_xangleSigma","mes_yangleSigma","dummy",true,true); + setSigmaTiltAngleCmd->SetDefaultUnit("deg"); + + setPitchCmd = new G4UIcmdWithADoubleAndUnit("/gun/pitch",this); + setPitchCmd->SetGuidance(" Set pitch angle of the generated muons (with unit)"); + setPitchCmd->SetParameterName("mes_pitch",true); + setPitchCmd->SetDefaultUnit("deg"); + + // setMuonPolarizCmd = new G4UIcmdWithAnInteger("/gun/muonpolarization",this); + // setMuonPolarizCmd->SetGuidance(" Set initial mu polariz: 0=transverse, 1=longitudinal "); + // setMuonPolarizCmd->SetParameterName("IniPol",true); + // setMuonPolarizCmd->SetDefaultValue(0) ; + + setMuonPolarizCmd = new G4UIcmdWith3Vector("/gun/muonPolarizVector",this); + setMuonPolarizCmd->SetGuidance("Set initial mu polarisation as a vector (without unit)"); + setMuonPolarizCmd->SetGuidance(" The vector does not have to be normalised to 1"); + setMuonPolarizCmd->SetParameterName("mes_polarisX","mes_polarisY","mes_polarisZ",true,true); + + setMuonPolarizFractionCmd = new G4UIcmdWithADouble("/gun/muonPolarizFraction",this); + setMuonPolarizFractionCmd->SetGuidance(" Set the fraction of the muon polarisation (in the range of -1 to 1),"); + setMuonPolarizFractionCmd->SetGuidance(" where fraction = (N_up_spin - N_down_spin) / (N_up_spin + N_down_spin)"); + setMuonPolarizFractionCmd->SetParameterName("mes_polarisFraction",true); + + setMuonDecayTimeCmd = new G4UIcmdWith3VectorAndUnit("/gun/decaytimelimits",this); + setMuonDecayTimeCmd->SetGuidance(" Set minimum and maximum decay time and the muon mean life "); + setMuonDecayTimeCmd->SetParameterName("decayMin","decayMax","decayTime",true,true); + setMuonDecayTimeCmd->SetDefaultUnit("ns"); + + setTurtleCmd = new G4UIcmdWithAString("/gun/turtlefilename",this); + setTurtleCmd->SetGuidance("Set the filename of the TURTLE input file."); + setTurtleCmd->SetGuidance("If this varialble is set, TURTLE input will be used for initial muons"); + setTurtleCmd->AvailableForStates(G4State_PreInit,G4State_Idle); + + setTurtleZ0Cmd = new G4UIcmdWithADoubleAndUnit("/gun/turtleZ0position",this); + setTurtleZ0Cmd->SetGuidance("Set the z0, with which the TURTLE input file has been generated."); + setTurtleZ0Cmd->AvailableForStates(G4State_PreInit,G4State_Idle); + setTurtleZ0Cmd->SetParameterName("mes_z0Turtle",true); + setTurtleZ0Cmd->SetDefaultUnit("mm"); + + setTurtleMomentumBite = new G4UIcmdWith3Vector("/gun/turtleMomentumBite",this); + setTurtleMomentumBite->SetGuidance(" Modify smearing of the turtle momentum bite. The first value is the mean momentum in MeV/c,"); + setTurtleMomentumBite->SetGuidance(" the second value is the smearing factor in per cent, by which the momentum bite,"); + setTurtleMomentumBite->SetGuidance(" will be increased/decreased around the mean momemtum. 100 per cent correspond to no"); + setTurtleMomentumBite->SetGuidance(" change, 0 per cent will create monoenergetic beam, 200 per cent will create a two times"); + setTurtleMomentumBite->SetGuidance(" broader beam. The third parameter is dummy."); + setTurtleMomentumBite->SetParameterName("mes_turtleMomentumP0","mes_turtleSmearingFactor","mes_turtleSmearingDummy",true,true); + + + setTurtleEventNrCmd = new G4UIcmdWithAnInteger("/gun/turtleFirstEventNr",this); + setTurtleEventNrCmd->SetGuidance("Set the line number that should be taken as the first event from the turtle input file."); + setTurtleEventNrCmd->SetParameterName("mes_turtleFirstEvent",true); + setTurtleEventNrCmd->AvailableForStates(G4State_PreInit,G4State_Idle); + setTurtleEventNrCmd->SetDefaultValue(0) ; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... + +musrPrimaryGeneratorMessenger::~musrPrimaryGeneratorMessenger() +{ + delete setvertexCmd; + delete setvertexSigmaCmd; + delete setvertexBoundaryCmd; + delete setKEnergyCmd; + delete setMomentumCmd; + delete setMomentumSmearingCmd; + delete setMomentumBoundaryCmd; + delete setTiltAngleCmd; + delete setSigmaTiltAngleCmd; + delete setPitchCmd; + delete setMuonPolarizCmd; + delete setMuonPolarizFractionCmd; + delete setMuonDecayTimeCmd; + delete setTurtleCmd; + delete setTurtleZ0Cmd; + delete setTurtleMomentumBite; + delete setTurtleEventNrCmd; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... + +void musrPrimaryGeneratorMessenger::SetNewValue(G4UIcommand * command,G4String newValue) +{ + if( command == setvertexCmd) + { musrAction->Setvertex(setvertexCmd->GetNew3VectorValue(newValue));} + if( command == setvertexSigmaCmd) + { musrAction->SetvertexSigma(setvertexSigmaCmd->GetNew3VectorValue(newValue));} + if( command == setvertexBoundaryCmd) + { musrAction->SetvertexBoundary(setvertexBoundaryCmd->GetNew3VectorValue(newValue));} + if( command == setKEnergyCmd) + { musrAction->SetKEnergy(setKEnergyCmd->GetNewDoubleValue(newValue));} + if( command == setMomentumCmd) + { musrAction->SetMomentum(setMomentumCmd->GetNewDoubleValue(newValue));} + if( command == setMomentumSmearingCmd) + { musrAction->SetMomentumSmearing(setMomentumSmearingCmd->GetNewDoubleValue(newValue));} + if( command == setMomentumBoundaryCmd) + { musrAction->SetMomentumBoundary(setMomentumBoundaryCmd->GetNew3VectorValue(newValue));} + if( command == setTiltAngleCmd) + { musrAction->SetTilt(setTiltAngleCmd->GetNew3VectorValue(newValue));} + if( command == setSigmaTiltAngleCmd) + { musrAction->SetSigmaTilt(setSigmaTiltAngleCmd->GetNew3VectorValue(newValue));} + if( command == setPitchCmd) + { musrAction->SetPitch(setPitchCmd->GetNewDoubleValue(newValue));} + if( command == setMuonPolarizCmd) + { musrAction->SetInitialMuonPolariz(setMuonPolarizCmd->GetNew3VectorValue(newValue));} + if( command == setMuonPolarizFractionCmd) + { musrAction->SetInitialPolarizFraction(setMuonPolarizFractionCmd->GetNewDoubleValue(newValue));} + if( command == setMuonDecayTimeCmd) + { musrAction->SetMuonDecayTimeLimits(setMuonDecayTimeCmd->GetNew3VectorValue(newValue)); } + if( command == setTurtleCmd) + { musrAction->SetTurtleInput(newValue); } + if( command == setTurtleZ0Cmd) + { musrAction->SetTurtleZ0(setTurtleZ0Cmd->GetNewDoubleValue(newValue)); } + if( command == setTurtleMomentumBite) + { musrAction-> SetTurtleMomentumBite(setTurtleMomentumBite->GetNew3VectorValue(newValue)); } + if( command == setTurtleEventNrCmd) + { musrAction->SetTurtleInputFileToEventNo(setTurtleEventNrCmd->GetNewIntValue(newValue));} +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... + diff --git a/src/musrQuadrupole.cc b/src/musrQuadrupole.cc new file mode 100644 index 0000000..6bcdb48 --- /dev/null +++ b/src/musrQuadrupole.cc @@ -0,0 +1,87 @@ +#include "musrQuadrupole.hh" +#include "musrParameters.hh" + + +musrQuadrupole::musrQuadrupole(G4double halflengthVal, G4double fieldRadiusVal, G4double gradientVal, G4double fringeFactorVal, G4LogicalVolume* logVolume, G4ThreeVector positionOfTheCenter) : F04ElementField(positionOfTheCenter, logVolume) +{ + G4cout << "\n-----------------------------------------------------------" + << "\n Quadrupole field " + << "\n-----------------------------------------------------------" + << G4endl; + + gradient = gradientVal; //*(tesla/m); + fieldRadius = fieldRadiusVal; //*mm; + halflength = halflengthVal; //*mm; + enge = BLEngeFunction(ENGE_QUAD); + + G4double fringeFactor = fringeFactorVal; // the default should be 1. + G4bool fringe = true; if (fringeFactor==0.) {fringe=false;} + fringeDepth = fringeFactor * fieldRadius * 2.0; + + if (!fringe) { + enge.set(0,0,0,0,0,0); + fringeMaxZ = halflength; + } + else { + for(int i=0; i<1000; ++i) { + fringeMaxZ = i*fieldRadius/10.0 + halflength; + if(enge((fringeMaxZ-halflength)/fringeDepth) < FRINGE_ACCURACY) break; + } + } + + G4cout << " Field gradient set to "<< gradient/(tesla/m) << " T/m"<< G4endl; + G4cout << " Field radius set to " << fieldRadius/mm << " mm"<< G4endl; + G4cout << " Field halflength set to " << halflength/mm << " mm"< fieldRadius || fabs(local[2]) > fringeMaxZ) { return;} + + // apply enge() to the scalar potential phi=-G0*x*y*enge(z); + // B is minus its gradient. Handle both edges properly. + G4double G0 = gradient; + G4double f,fp; + if (fringeDepth!=0) { + double fringeZ = (fabs(local[2])-halflength)/fringeDepth; + f = enge(fringeZ); + fp = enge.prime(fringeZ)/fringeDepth; + } + else { + f = ( fabs(local[2]) > halflength) ? 0:1; + fp = 0; + } + G4ThreeVector B(G0*f*local[1],G0*f*local[0],G0*fp*local[0]*local[1]); + if(local[2] < 0.0) B[2] = -B[2]; + + G4ThreeVector finalField(B[0],B[1],B[2]); + finalField = global2local.Inverse().TransformAxis(finalField); + + field[0] += finalField.x(); + field[1] += finalField.y(); + field[2] += finalField.z(); + + // G4cout<<"musrQuadrupole.cc: field: ("<GetCurrentRun()->GetRunID(); + char RootOutputFileName[200]; + sprintf(RootOutputFileName, "data/musr_%i.root", tmpRunNr); + rootFile=new TFile(RootOutputFileName,"recreate"); + rootTree=new TTree("t1","a simple Tree with simple variables"); + if (store_runID) {rootTree->Branch("runID",&runID_t,"runID/I");} + if (store_eventID) {rootTree->Branch("eventID",&eventID_t,"eventID/I");} + if (store_weight) {rootTree->Branch("weight",&weight_t,"weight/D");} + if (store_BFieldAtDecay) {rootTree->Branch("BFieldAtDecay",&B_t,"Bx/D:By:Bz:B3:B4:B5");} + if (store_muIniPosX) {rootTree->Branch("muIniPosX",&muIniPosX_t,"muIniPosX/D");} + if (store_muIniPosY) {rootTree->Branch("muIniPosY",&muIniPosY_t,"muIniPosY/D");} + if (store_muIniPosZ) {rootTree->Branch("muIniPosZ",&muIniPosZ_t,"muIniPosZ/D");} + if (store_muIniMomX) {rootTree->Branch("muIniMomX",&muIniMomX_t,"muIniMomX/D");} + if (store_muIniMomY) {rootTree->Branch("muIniMomY",&muIniMomY_t,"muIniMomY/D");} + if (store_muIniMomZ) {rootTree->Branch("muIniMomZ",&muIniMomZ_t,"muIniMomZ/D");} + if (store_muIniPolX) {rootTree->Branch("muIniPolX",&muIniPolX_t,"muIniPolX/D");} + if (store_muIniPolY) {rootTree->Branch("muIniPolY",&muIniPolY_t,"muIniPolY/D");} + if (store_muIniPolZ) {rootTree->Branch("muIniPolZ",&muIniPolZ_t,"muIniPolZ/D");} + if (store_muDecayDetID) {rootTree->Branch("muDecayDetID",&muDecayDetID_t,"muDecayDetID/I");} + if (store_muDecayPosX) {rootTree->Branch("muDecayPosX",&muDecayPosX_t,"muDecayPosX/D");} + if (store_muDecayPosY) {rootTree->Branch("muDecayPosY",&muDecayPosY_t,"muDecayPosY/D");} + if (store_muDecayPosZ) {rootTree->Branch("muDecayPosZ",&muDecayPosZ_t,"muDecayPosZ/D");} + if (store_muDecayTime) {rootTree->Branch("muDecayTime",&muDecayTime_t,"muDecayTime/D");} + if (store_muDecayPolX) {rootTree->Branch("muDecayPolX",&muDecayPolX_t,"muDecayPolX/D");} + if (store_muDecayPolY) {rootTree->Branch("muDecayPolY",&muDecayPolY_t,"muDecayPolY/D");} + if (store_muDecayPolZ) {rootTree->Branch("muDecayPolZ",&muDecayPolZ_t,"muDecayPolZ/D");} + if (store_muTargetTime) {rootTree->Branch("muTargetTime",&muTargetTime_t,"muTargetTime/D");} + if (store_muTargetPolX) {rootTree->Branch("muTargetPolX",&muTargetPolX_t,"muTargetPolX/D");} + if (store_muTargetPolY) {rootTree->Branch("muTargetPolY",&muTargetPolY_t,"muTargetPolY/D");} + if (store_muTargetPolZ) {rootTree->Branch("muTargetPolZ",&muTargetPolZ_t,"muTargetPolZ/D");} + if (store_muM0Time) {rootTree->Branch("muM0Time",&muM0Time_t,"muM0Time/D");} + if (store_muM0PolX) {rootTree->Branch("muM0PolX",&muM0PolX_t,"muM0PolX/D");} + if (store_muM0PolY) {rootTree->Branch("muM0PolY",&muM0PolY_t,"muM0PolY/D");} + if (store_muM0PolZ) {rootTree->Branch("muM0PolZ",&muM0PolZ_t,"muM0PolZ/D");} + if (store_muM1Time) {rootTree->Branch("muM1Time",&muM1Time_t,"muM1Time/D");} + if (store_muM1PolX) {rootTree->Branch("muM1PolX",&muM1PolX_t,"muM1PolX/D");} + if (store_muM1PolY) {rootTree->Branch("muM1PolY",&muM1PolY_t,"muM1PolY/D");} + if (store_muM1PolZ) {rootTree->Branch("muM1PolZ",&muM1PolZ_t,"muM1PolZ/D");} + if (store_muM2Time) {rootTree->Branch("muM2Time",&muM2Time_t,"muM2Time/D");} + if (store_muM2PolX) {rootTree->Branch("muM2PolX",&muM2PolX_t,"muM2PolX/D");} + if (store_muM2PolY) {rootTree->Branch("muM2PolY",&muM2PolY_t,"muM2PolY/D");} + if (store_muM2PolZ) {rootTree->Branch("muM2PolZ",&muM2PolZ_t,"muM2PolZ/D");} + if (store_posIniMomX) {rootTree->Branch("posIniMomX",&posIniMomx_t,"posIniMomX/D");} + if (store_posIniMomY) {rootTree->Branch("posIniMomY",&posIniMomy_t,"posIniMomY/D");} + if (store_posIniMomZ) {rootTree->Branch("posIniMomZ",&posIniMomz_t,"posIniMomZ/D");} + // if (store_globalTime) {rootTree->Branch("globalTime",&globalTime_t,"globalTime/D");} + // if (store_fieldValue) {rootTree->Branch("fieldValue",&fieldValue_t,"fieldValue/D");} + if (store_fieldNomVal) { + rootTree->Branch("nFieldNomVal",&nFieldNomVal,"nFieldNomVal/I"); + rootTree->Branch("fieldNomVal",&fieldNomVal,"fieldNomVal[nFieldNomVal]/D"); + } + if (store_fieldIntegralBx) {rootTree->Branch("BxIntegral",&BxIntegral_t,"BxIntegral/D");} + if (store_fieldIntegralBy) {rootTree->Branch("ByIntegral",&ByIntegral_t,"ByIntegral/D");} + if (store_fieldIntegralBz) {rootTree->Branch("BzIntegral",&BzIntegral_t,"BzIntegral/D");} + if (store_fieldIntegralBz1) {rootTree->Branch("BzIntegral1",&BzIntegral1_t,"BzIntegral1/D");} + if (store_fieldIntegralBz2) {rootTree->Branch("BzIntegral2",&BzIntegral2_t,"BzIntegral2/D");} + if (store_fieldIntegralBz3) {rootTree->Branch("BzIntegral3",&BzIntegral3_t,"BzIntegral3/D");} + + rootTree->Branch("det_n",&det_n,"det_n/I"); + if (store_det_ID) {rootTree->Branch("det_ID",&det_ID,"det_ID[det_n]/I");} + if (store_det_edep) {rootTree->Branch("det_edep",&det_edep,"det_edep[det_n]/D");} + if (store_det_edep_el) {rootTree->Branch("det_edep_el",&det_edep_el,"det_edep_el[det_n]/D");} + if (store_det_edep_pos) {rootTree->Branch("det_edep_pos",&det_edep_pos,"det_edep_pos[det_n]/D");} + if (store_det_edep_gam) {rootTree->Branch("det_edep_gam",&det_edep_gam,"det_edep_gam[det_n]/D");} + if (store_det_edep_mup) {rootTree->Branch("det_edep_mup",&det_edep_mup,"det_edep_mup[det_n]/D");} + if (store_det_nsteps) {rootTree->Branch("det_nsteps",&det_nsteps,"det_nsteps[det_n]/I");} + if (store_det_length) {rootTree->Branch("det_length",&det_length,"det_length[det_n]/D");} + if (store_det_start) {rootTree->Branch("det_time_start",&det_time_start,"det_time_start[det_n]/D");} + if (store_det_end) {rootTree->Branch("det_time_end",&det_time_end,"det_time_end[det_n]/D");} + if (store_det_x) {rootTree->Branch("det_x",&det_x,"det_x[det_n]/D");} + if (store_det_y) {rootTree->Branch("det_y",&det_y,"det_y[det_n]/D");} + if (store_det_z) {rootTree->Branch("det_z",&det_z,"det_z[det_n]/D");} + if (store_det_kine) {rootTree->Branch("det_kine",&det_kine,"det_kine[det_n]/D");} + if (store_det_VrtxKine) {rootTree->Branch("det_VrtxKine",&det_VrtxKine,"det_VrtxKine[det_n]/D");} + if (store_det_VrtxX) {rootTree->Branch("det_VrtxX",&det_VrtxX,"det_VrtxX[det_n]/D");} + if (store_det_VrtxY) {rootTree->Branch("det_VrtxY",&det_VrtxY,"det_VrtxY[det_n]/D");} + if (store_det_VrtxZ) {rootTree->Branch("det_VrtxZ",&det_VrtxZ,"det_VrtxZ[det_n]/D");} + if (store_det_VrtxVolID){rootTree->Branch("det_VrtxVolID",&det_VrtxVolID,"det_VrtxVolID[det_n]/I");} + if (store_det_VrtxProcID){rootTree->Branch("det_VrtxProcID",&det_VrtxProcID,"det_VrtxProcID[det_n]/I");} + if (store_det_VrtxTrackID){rootTree->Branch("det_VrtxTrackID",&det_VrtxTrackID,"det_VrtxTrackID[det_n]/I");} + if (store_det_VrtxParticleID){rootTree->Branch("det_VrtxParticleID",&det_VrtxParticleID,"det_VrtxParticleID[det_n]/I");} + if (store_det_VvvKine) {rootTree->Branch("det_VvvKine",&det_VvvKine,"det_VvvKine[det_n]/D");} + if (store_det_VvvX) {rootTree->Branch("det_VvvX",&det_VvvX,"det_VvvX[det_n]/D");} + if (store_det_VvvY) {rootTree->Branch("det_VvvY",&det_VvvY,"det_VvvY[det_n]/D");} + if (store_det_VvvZ) {rootTree->Branch("det_VvvZ",&det_VvvZ,"det_VvvZ[det_n]/D");} + if (store_det_VvvVolID){rootTree->Branch("det_VvvVolID",&det_VvvVolID,"det_VvvVolID[det_n]/I");} + if (store_det_VvvProcID){rootTree->Branch("det_VvvProcID",&det_VvvProcID,"det_VvvProcID[det_n]/I");} + if (store_det_VvvTrackID){rootTree->Branch("det_VvvTrackID",&det_VvvTrackID,"det_VvvTrackID[det_n]/I");} + if (store_det_VvvParticleID){rootTree->Branch("det_VvvParticleID",&det_VvvParticleID,"det_VvvParticleID[det_n]/I");} + + if (boolIsAnySpecialSaveVolumeDefined) { + rootTree->Branch("save_n",&save_n,"save_n/I"); + rootTree->Branch("save_detID",&save_detID,"save_detID[save_n]/I"); + rootTree->Branch("save_particleID",&save_particleID,"save_particleID[save_n]/I"); + rootTree->Branch("save_ke",&save_ke,"save_ke[save_n]/D"); + rootTree->Branch("save_x",&save_x,"save_x[save_n]/D"); + rootTree->Branch("save_y",&save_y,"save_y[save_n]/D"); + rootTree->Branch("save_z",&save_z,"save_z[save_n]/D"); + rootTree->Branch("save_px",&save_px,"save_px[save_n]/D"); + rootTree->Branch("save_py",&save_py,"save_py[save_n]/D"); + rootTree->Branch("save_pz",&save_pz,"save_pz[save_n]/D"); + } + + // htest1 = new TH1F("htest1","The debugging histogram 1",50,-4.,4.); + // htest2 = new TH1F("htest2","The debugging histogram 2",50,0.,3.142); + htest1 = new TH2F("htest1","x, y",50,-200.,200.,50,-200.,200.); + htest2 = new TH2F("htest2","R, z",50,0.,250.,50,-150.,150.); + htest3 = new TH1F("htest3","Energy in MeV",55,0.,55.); + htest4 = new TH1F("htest4","Radioactive electron kinetic energy",250,0.,2.5); + htest5 = new TH1F("htest5","The debugging histogram 5",50,-4.,4.); + htest6 = new TH1F("htest6","The debugging histogram 6",50,0.,3.142); + htest7 = new TH1F("htest7","The debugging histogram 7",50,-4.,4.); + htest8 = new TH1F("htest8","The debugging histogram 8",50,0.,3.142); + + G4cout << "musrRootOutput::BeginOfRunAction() The Root tree and branches were defined."<Write(); + htest1->Write(); + htest2->Write(); + htest3->Write(); + htest4->Write(); + htest5->Write(); + htest6->Write(); + htest7->Write(); + htest8->Write(); + // Variables exported from Geant simulation to the Root output + // static const Int_t nGeantParamD=10; + TVectorD TVector_GeantParametersD(maxNGeantParameters); + for (Int_t i=0; iClose(); + G4cout<<"musrRootOutput::EndOfRunAction() - Root tree written out."<Fill(atan2(posIniMomy_t,posIniMomx_t)); + htest6->Fill(atan2(sqrt(posIniMomx_t*posIniMomx_t+posIniMomy_t*posIniMomy_t),posIniMomz_t)); + if (weight_t>0.) { + rootTree->Fill(); + } +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrRootOutput::ClearAllRootVariables() { + runID_t=-1000; + eventID_t=-1000; + weight_t=1.; + B_t[0]=-1000.;B_t[1]=-1000.;B_t[2]=-1000.;B_t[3]=-1000.;B_t[4]=-1000.;B_t[5]=-1000.; + muIniPosX_t=-1000; muIniPosY_t=-1000; muIniPosZ_t=-1000; + muIniMomX_t=-1000; muIniMomY_t=-1000; muIniMomZ_t=-1000; + muIniPolX_t=-1000; muIniPolY_t=-1000; muIniPolZ_t=-1000; + muDecayDetID_t=-1000; + muDecayPolX_t=-1000; muDecayPolY_t=-1000; muDecayPolZ_t=-1000; + muTargetTime_t=-1000; muTargetPolX_t=-1000; muTargetPolY_t=-1000; muTargetPolZ_t=-1000; + muM0Time_t=-1000; muM0PolX_t=-1000; muM0PolY_t=-1000; muM0PolZ_t=-1000; + muM1Time_t=-1000; muM1PolX_t=-1000; muM1PolY_t=-1000; muM1PolZ_t=-1000; + muM2Time_t=-1000; muM2PolX_t=-1000; muM2PolY_t=-1000; muM2PolZ_t=-1000; + muDecayPosX_t=-1000;muDecayPosY_t=-1000;muDecayPosZ_t=-1000; + muDecayTime_t=-1000; + posIniMomx_t=-1000;posIniMomy_t=-1000;posIniMomz_t=-1000; + BxIntegral_t = -1000; ByIntegral_t = -1000; BzIntegral_t = -1000; + BzIntegral1_t = -1000; BzIntegral2_t = -1000; BzIntegral3_t = -1000; + det_n=0; + save_n=0; + +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + + +void musrRootOutput::SetVolumeIDMapping(std::string logivol, int volumeID) { + // This function assigns a unique number to each sensitive detector name. + // The numbers are used in the root tree, as it is easier to work with numbers + // rather than with strings. + if (SensDetectorMapping[logivol]) { + char message[200]; + sprintf(message,"musrRootOutput::SetVolumeIDMapping: Sensitive volume %s already assigned",logivol.c_str()); + musrErrorMessage::GetInstance()->musrError(FATAL,message,false); + } + else{ + SensDetectorMapping[logivol]=volumeID; + } +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +G4int musrRootOutput::ConvertVolumeToID(std::string logivol) { + G4int volumeID = SensDetectorMapping[logivol]; + if (volumeID==0) { + char message[200]; + sprintf(message,"musrRootOutput::ConvertVolumeToID: No ID number assigned to sensitive volume %s .",logivol.c_str()); + musrErrorMessage::GetInstance()->musrError(SERIOUS,message,true); + } + return volumeID; +} + + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +G4int musrRootOutput::ConvertProcessToID(std::string processName) { + G4int processID = ProcessIDMapping[processName]; + if (processID==0) { + char message[200]; + sprintf(message,"musrRootOutput::ConvertProcessToID: No ID number assigned to the process \"%s\" .",processName.c_str()); + musrErrorMessage::GetInstance()->musrError(WARNING,message,true); + } + return processID; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrRootOutput::SetSaveDetectorInfo (G4int ID, G4int particleID, G4double ke, + G4double x, G4double y, G4double z, G4double px, G4double py, G4double pz) { + if (save_n>=save_nMax) { + char message[200]; + sprintf(message,"musrRootOutput.cc::SetSaveDetectorInfo(): more \"save\" hits then allowed: save_nMax=%i",save_nMax); + musrErrorMessage::GetInstance()->musrError(SERIOUS,message,true); + } + else { + save_detID[save_n]=ID; + save_particleID[save_n]=particleID; + save_ke[save_n]=ke/MeV; + save_x[save_n]=x/mm; + save_y[save_n]=y/mm; + save_z[save_n]=z/mm; + save_px[save_n]=px/MeV; + save_py[save_n]=py/MeV; + save_pz[save_n]=pz/MeV; + + save_n++; + } +} + +void musrRootOutput::SetFieldNomVal(G4int i, G4double value) { + if (imusrError(SERIOUS,message,true); + } +} + + +void musrRootOutput::SetDetectorInfo (G4int nDetectors, G4int ID, G4int particleID, G4double edep, + G4double edep_el, G4double edep_pos, + G4double edep_gam, G4double edep_mup,G4int nsteps, G4double length, G4double t1, + G4double t2, G4double x, G4double y, G4double z, + G4double ek, G4double ekVertex, G4double xVertex, G4double yVertex, G4double zVertex, + G4int idVolVertex, G4int idProcVertex, G4int idTrackVertex) +{ + if ((nDetectors<0)||(nDetectors>=(det_nMax-1))) { + char message[200]; + sprintf(message,"musrRootOutput.cc::SetDetectorInfo: nDetectors %i is larger than det_nMax = %i",nDetectors,det_nMax); + musrErrorMessage::GetInstance()->musrError(SERIOUS,message,false); + return; + } + else { + det_n=nDetectors+1; + det_ID[nDetectors]=ID; + det_edep[nDetectors]=edep/MeV; + det_edep_el[nDetectors]=edep_el/MeV; + det_edep_pos[nDetectors]=edep_pos/MeV; + det_edep_gam[nDetectors]=edep_gam/MeV; + det_edep_mup[nDetectors]=edep_mup/MeV; + det_nsteps[nDetectors]=nsteps; + det_length[nDetectors]=length/mm; + det_time_start[nDetectors]=t1/microsecond; + det_time_end[nDetectors]=t2/microsecond; + det_x[nDetectors]=x/mm; + det_y[nDetectors]=y/mm; + det_z[nDetectors]=z/mm; + det_kine[nDetectors]=ek/MeV; + det_VrtxKine[nDetectors]=ekVertex/MeV; + det_VrtxX[nDetectors]=xVertex/mm; + det_VrtxY[nDetectors]=yVertex/mm; + det_VrtxZ[nDetectors]=zVertex/mm; + det_VrtxVolID[nDetectors]=idVolVertex; + det_VrtxProcID[nDetectors]=idProcVertex; + det_VrtxTrackID[nDetectors]=idTrackVertex; + det_VrtxParticleID[nDetectors]=particleID; + } +} + +void musrRootOutput::SetDetectorInfoVvv (G4int nDetectors, + G4double ekVertex, G4double xVertex, G4double yVertex, G4double zVertex, + G4int idVolVertex, G4int idProcVertex, G4int idTrackVertex, G4int particleID) { + if ((nDetectors<0)||(nDetectors>=(det_nMax-1))) { + char message[200]; + sprintf(message,"musrRootOutput.cc::SetDetectorInfoVvv: nDetectors %i is larger than det_nMax = %i",nDetectors,det_nMax); + musrErrorMessage::GetInstance()->musrError(SERIOUS,message,false); + return; + } + else { + det_VvvKine[nDetectors]=ekVertex/MeV; + det_VvvX[nDetectors]=xVertex/mm; + det_VvvY[nDetectors]=yVertex/mm; + det_VvvZ[nDetectors]=zVertex/mm; + det_VvvVolID[nDetectors]=idVolVertex; + det_VvvProcID[nDetectors]=idProcVertex; + det_VvvTrackID[nDetectors]=idTrackVertex; + det_VvvParticleID[nDetectors]=particleID; + } +} diff --git a/src/musrRunAction.cc b/src/musrRunAction.cc new file mode 100644 index 0000000..1912364 --- /dev/null +++ b/src/musrRunAction.cc @@ -0,0 +1,100 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +// Make G4Timer appear first! +#include "G4Timer.hh" +#include "musrRunAction.hh" +#include "musrEventAction.hh" +#include "musrSteppingAction.hh" +#include "G4Run.hh" +#include "musrErrorMessage.hh" +#include "F04GlobalField.hh" + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +musrRunAction::musrRunAction() { + timer = new G4Timer; +} + + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +musrRunAction::~musrRunAction() { + delete timer; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrRunAction::BeginOfRunAction(const G4Run* aRun) { + timer->Start(); + G4int run_id= aRun->GetRunID(); + // if (run_id%100 == 0) { + G4cout << "### Run " << run_id << G4endl; + musrRootOutput::GetRootInstance()->StoreGeantParameter(6,run_id); + musrRootOutput::GetRootInstance()->BeginOfRunAction(); + + // Initiate global electromagnetic field (if it exists): + if (F04GlobalField::Exists()) { + FieldList* fields = F04GlobalField::getObject()->getFields(); + + if (fields) { + if (fields->size()>0) { + G4int jjj=0; + G4cout<<"\n------------ The following fields were defined: ----------------"<begin(); i!=fields->end(); ++i) { + (*i)->construct(); + // G4cout<<"\t==> "<<(*i)->GetElementFieldName()<GetNominalFieldValue(); + musrRootOutput::GetRootInstance()->SetFieldNomVal(jjj,nomFieldValue); + jjj++; + } + G4cout<<"-----------------------------------------------------------------"<PrintFieldAtRequestedPoints(); + } + + // initialise the "boolIsVvvInfoRequested" variable in the musrSteppingAction.cc and musrScintSD.cc + G4bool boolIsVvvInfoRequested = false; + if ((musrRootOutput::store_det_VvvKine)||(musrRootOutput::store_det_VvvX)|| + (musrRootOutput::store_det_VvvY)||(musrRootOutput::store_det_VvvZ)|| + (musrRootOutput::store_det_VvvVolID)||(musrRootOutput::store_det_VvvProcID)|| + (musrRootOutput::store_det_VvvTrackID)||(musrRootOutput::store_det_VvvParticleID)) { + boolIsVvvInfoRequested = true; + } + musrSteppingAction::GetInstance()->SetVvvInfoRequested(boolIsVvvInfoRequested); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrRunAction::EndOfRunAction(const G4Run* aRun) { + musrRootOutput::GetRootInstance()->StoreGeantParameter(5,aRun->GetNumberOfEvent()); + musrRootOutput::GetRootInstance()->EndOfRunAction(); + + if (F04GlobalField::Exists()) { + F04GlobalField* myGlobalField = F04GlobalField::getObject(); //Was causing seg. fault when called here + if (myGlobalField!=NULL) {delete myGlobalField;} + } + + musrErrorMessage::GetInstance()->PrintErrorSummary(); + + timer->Stop(); + G4cout << "musrRunAction::EndOfRunAction:"< +#include +#include + +G4Allocator musrScintHitAllocator; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +musrScintHit::musrScintHit() { +} + +G4int musrScintHit::ScintMultihit=0; +G4int musrScintHit::runIDoldScint=-1; +G4int musrScintHit::eventIDoldScint=-1; +G4int musrScintHit::NIS=0; +G4int musrScintHit::ScintChamberNbold=-1; +G4int musrScintHit::verboseLevel=0; + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +musrScintHit::~musrScintHit() { + //save the Tree header. The file will be automatically closed + //when going out of the function scope + // rootTree->Write(); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +musrScintHit::musrScintHit(const musrScintHit& right) + : G4VHit() +{ + particleName = right.particleName; + trackID = right.trackID; + edep = right.edep; + pre_pos = right.pre_pos; + pol = right.pol; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +const musrScintHit& musrScintHit::operator=(const musrScintHit& right) +{ + particleName = right.particleName; + trackID = right.trackID; + edep = right.edep; + pre_pos = right.pre_pos; + pol = right.pol; + return *this; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +G4int musrScintHit::operator==(const musrScintHit& right) const +{ + return (this==&right) ? 1 : 0; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrScintHit::Draw() +{ + G4VVisManager* pVVisManager = G4VVisManager::GetConcreteInstance(); + if(pVVisManager) + { + G4Circle circle(pre_pos); + circle.SetScreenSize(0.04); + circle.SetFillStyle(G4Circle::filled); + G4Colour colour(1.,0.,0.); + G4VisAttributes attribs(colour); + circle.SetVisAttributes(attribs); + pVVisManager->Draw(circle); + } +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrScintHit::Print() +{ + if (verboseLevel>2) G4cout<<"VERBOSE 3: Kamil: musrScintHit::Print()"<GetCurrentEvent()->GetEventID(); + runID = fRunManager->GetCurrentRun()->GetRunID(); + G4int ScintMultihitSwitch=0; + + if (runID != runIDoldScint) { + NIS=0; + ScintMultihit = 0; + eventIDoldScint = -1; + ScintChamberNbold = -1; + } + + //cks if (particleName== "e+" and (eventIDoldScint != eventID or ScintChamberNbold != IBchamberNb)) { + if (particleName== "e+") { + if (eventIDoldScint == eventID) { + ScintMultihit++; + ScintMultihitSwitch=1; + } + NIS++; + + G4FieldManager *fMgr=G4TransportationManager::GetTransportationManager()->GetFieldManager(); + point[0]=0.; + point[1]=0.; + point[2]=0.; + B[2]=0.0; + if(!fMgr->DoesFieldChangeEnergy()) { //then we have a magnetic field + mfield = fMgr->GetDetectorField(); + mfield->GetFieldValue(point,B); + B[0]=B[0]/tesla; + B[1]=B[1]/tesla; + B[2]=B[2]/tesla; + } + // G4cout << " Segment: " << IBchamberNb << G4endl; + // G4cout <<"Position " << pos.x()/cm<<" "< // needed for the sort() function +#include "G4VProcess.hh" // needed for the degugging message of the process name +#include "G4RunManager.hh" +#include "G4Run.hh" +#include "musrParameters.hh" +#include "musrErrorMessage.hh" +#include "musrSteppingAction.hh" +#include + +//bool myREMOVEfunction (int i,int j) { return (i::iterator i1, std::map::iterator m2) { +// return ( (*i1).first()<(*i2).second() ); +//} +// +//bool timeOrdering2 (std::pair p1, std::pair p2) { +// return ( p1.first()1) G4cout<<"VERBOSE 2: musrScintSD::Initialize\n"; + scintCollection = new musrScintHitsCollection + (SensitiveDetectorName,collectionName[0]); + static G4int HCID = -1; + if(HCID<0) { + HCID = G4SDManager::GetSDMpointer()->GetCollectionID(collectionName[0]); + if (verboseLevel>1) G4cout<<"VERBOSE 2: musrScintSD::HCID was <0\n, now HCID="<AddHitsCollection( HCID, scintCollection ); + myStoreOnlyEventsWithHits = musrParameters::storeOnlyEventsWithHits; + mySignalSeparationTime = musrParameters::signalSeparationTime; + myStoreOnlyTheFirstTimeHit= musrParameters::storeOnlyTheFirstTimeHit; + myStoreOnlyEventsWithHitInDetID = musrParameters::storeOnlyEventsWithHitInDetID; + musrSteppingAction* myMusrSteppingAction = musrSteppingAction::GetInstance(); + boolIsVvvInfoRequested = myMusrSteppingAction->IsVvvInfoRequested(); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +G4bool musrScintSD::ProcessHits(G4Step* aStep,G4TouchableHistory*) +{ + if (verboseLevel>1) G4cout<<"VERBOSE 2: musrScintSD::ProcessHits\n"; + G4double edep = aStep->GetTotalEnergyDeposit(); + if(edep==0.) { + return false; + } + + G4Track* aTrack = aStep->GetTrack(); + G4String actualVolume=aTrack->GetVolume()->GetLogicalVolume()->GetName(); + + // If requested, store only the hit that happened first (usefull for some special studies, not for a serious simulation) + if (myStoreOnlyTheFirstTimeHit) { + G4int NbHits = scintCollection->entries(); + if (NbHits>0) { + aTrack->SetTrackStatus(fStopAndKill); + return false; + } + } + + musrScintHit* newHit = new musrScintHit(); + newHit->SetParticleName (aTrack->GetDefinition()->GetParticleName()); + G4int particleID = aTrack->GetDefinition()->GetPDGEncoding(); + newHit->SetParticleID (particleID); + newHit->SetEdep (edep); + newHit->SetPrePos (aStep->GetPreStepPoint()->GetPosition()); + newHit->SetPostPos (aStep->GetPostStepPoint()->GetPosition()); + newHit->SetPol (aTrack->GetPolarization()); + G4LogicalVolume* hitLogicalVolume = aTrack->GetVolume()->GetLogicalVolume(); + newHit->SetLogVolName(hitLogicalVolume->GetName()); + newHit->SetGlobTime(aTrack->GetGlobalTime()); + // Warning - aStep->IsFirstStepInVolume() only available in Geant version >= 4.8.2 ! + // newHit->SetFirstStepInVolumeFlag(aStep->IsFirstStepInVolume()); + // newHit->SetLastStepInVolumeFlag(aStep->IsLastStepInVolume()); + newHit->SetKineticEnergy(aTrack->GetKineticEnergy()); + // newHit->SetKineticEnergy(aTrack->GetKineticEnergy()+edep); + G4double vertexKineticEnergy = aTrack->GetVertexKineticEnergy(); + newHit->SetVertexKineticEnergy(vertexKineticEnergy); + G4ThreeVector vertexPosition = aTrack->GetVertexPosition(); + newHit->SetVertexPosition(vertexPosition); + const G4LogicalVolume* vertexLogicalVolume = aTrack->GetLogicalVolumeAtVertex(); + G4String vertexLogicalVolumeName = vertexLogicalVolume->GetName(); + newHit->SetLogicalVolumeAtVertex(vertexLogicalVolumeName); + G4String processName; + if ((aTrack->GetCreatorProcess())!=0) { processName=aTrack->GetCreatorProcess()->GetProcessName(); } + else {processName="initialParticle";} //if no process found, the track comes from the generated particle + newHit->SetCreatorProcessName(processName); + G4int trackID = aTrack->GetTrackID(); + newHit->SetTrackID (trackID); + newHit->SetStepLength (aStep->GetStepLength()); + + scintCollection->insert( newHit ); + // newHit->Print(); + newHit->Draw(); + return true; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrScintSD::EndOfEvent(G4HCofThisEvent*) { + if (verboseLevel>1) { + G4cout<<"VERBOSE 2: musrScintSD::EndOfEvent"<entries(); + G4cout << "\n-------->Hits Collection: in this event they are " << NbHits + << " hits in the scint chambers: " << G4endl; + } + + // Positron_momentum_already_stored=0; + musrRootOutput* myRootOutput = musrRootOutput::GetRootInstance(); + + G4RunManager* fRunManager = G4RunManager::GetRunManager(); + myRootOutput->SetRunID(fRunManager->GetCurrentRun()->GetRunID()); + myRootOutput->SetEventID(fRunManager->GetCurrentEvent()->GetEventID()); + + G4int NbHits = scintCollection->entries(); + + if (myStoreOnlyEventsWithHits) { + if (NbHits<=0) { + return; + } + else if (myStoreOnlyEventsWithHitInDetID!=0) { + for (G4int i=0; iGetLogVolName(); + G4int aHitVolumeID = myRootOutput->ConvertVolumeToID(aHitVolumeName); + if (aHitVolumeID==myStoreOnlyEventsWithHitInDetID) break; // hit in the requested detector was identified + if (i==(NbHits-1)) return; // no hit identified in the requested detector + } + } + } + + // Sort out hits and fill them into root + if (NbHits>0) { + const G4int det_IDmax = musrRootOutput::det_nMax; + G4double det_edep[det_IDmax]; + G4int det_nsteps[det_IDmax]; + G4double det_length[det_IDmax]; + G4int det_ID[det_IDmax]; + G4double det_edep_el[det_IDmax]; + G4double det_edep_pos[det_IDmax]; + G4double det_edep_gam[det_IDmax]; + G4double det_edep_mup[det_IDmax]; + G4double det_time_start[det_IDmax]; + G4double det_time_end[det_IDmax]; + G4double det_x[det_IDmax]; + G4double det_y[det_IDmax]; + G4double det_z[det_IDmax]; + G4double det_kine[det_IDmax]; + G4double det_VrtxKine[det_IDmax]; + G4double det_VrtxX[det_IDmax]; + G4double det_VrtxY[det_IDmax]; + G4double det_VrtxZ[det_IDmax]; + G4int det_VrtxVolID[det_IDmax]; + G4int det_VrtxProcID[det_IDmax]; + G4int det_VrtxTrackID[det_IDmax]; + G4int det_VrtxParticleID[det_IDmax]; + G4int det_VvvTrackSign[det_IDmax]; + + // Sort hits according to the time. Using std::map is convenient, because it sorts + // its entries according to the key (the first variable of the pair). + std::multimap myHitTimeMapping; // "map" replaced by "multimap" (needed for radioactive decay, + // in which case times are huge and due to the limited rounding + // precision become equal --> map ignores the same "keys", + // multimap does not. + std::map::iterator it; + for (G4int i=0; iGetGlobalTime(); + // G4cout<<"Hit nr "<first; + // G4cout << " Value:" << it->second << "\n"; + G4int ii = it->second; // ii is the index of the hits, which is sorted according to time + musrScintHit* aHit = (*scintCollection)[ii]; + G4String aHitVolumeName = aHit->GetLogVolName(); + G4int aHitVolumeID = myRootOutput->ConvertVolumeToID(aHitVolumeName); + G4double aHitTime = aHit->GetGlobalTime(); + G4int aHitTrackID = aHit->GetTrackID(); + + // Loop over all already defined signals and check whether the hit falls into any of them + G4bool signalAssigned=false; + for (G4int j=0; jGetEdep(); + det_nsteps[j]++; + det_length[j] += aHit->GetStepLength(); + det_time_end[j] = aHitTime; + G4String aParticleName = aHit->GetParticleName(); + if (aParticleName=="e-") { + det_edep_el[j] += aHit->GetEdep(); + } else if (aParticleName=="e+") { + det_edep_pos[j] += aHit->GetEdep(); + } else if (aParticleName=="gamma") { + det_edep_gam[j] += aHit->GetEdep(); + } else if (aParticleName=="mu+") { + det_edep_mup[j] += aHit->GetEdep(); + } else { + char message[200]; + sprintf(message,"musrScintSD.cc::EndOfEvent(): untreated particle \"%s\" deposited energy.",aParticleName.c_str()); + musrErrorMessage::GetInstance()->musrError(WARNING,message,true); + } + // Check whether the signals consits of more then just one hit, in which case make the track ID negative: + if (abs(det_VrtxTrackID[j])!=aHitTrackID) { + det_VrtxTrackID[j]=-1*abs(det_VrtxTrackID[j]); + if (boolIsVvvInfoRequested) { + if (det_VvvTrackSign[j]==1) { + musrSteppingAction* myMusrSteppingAction = musrSteppingAction::GetInstance(); + if (!(myMusrSteppingAction->AreTracksCommingFromSameParent(aHitTrackID,abs(det_VrtxTrackID[j]),aHitVolumeName))) {det_VvvTrackSign[j]=-1;} + } + } + } + break; + } + } + if (!signalAssigned) { // The hit does not belong to any existing signal --> create a new signal. + // Check, whether the maximum number of signals was not exceeded: + if ( nSignals >= (det_IDmax-1) ) { + char message[200]; + sprintf(message,"musrScintSD.cc::EndOfEvent(): number of signals exceeds maximal allowed value."); + musrErrorMessage::GetInstance()->musrError(WARNING,message,true); + } + else { + det_edep[nSignals] = aHit->GetEdep(); + det_nsteps[nSignals] = 1; + det_length[nSignals] = aHit->GetStepLength(); + det_ID[nSignals] = aHitVolumeID; + det_time_start[nSignals] = aHitTime; + det_time_end[nSignals] = aHitTime; + det_edep_el[nSignals] = 0; + det_edep_pos[nSignals] = 0; + det_edep_gam[nSignals] = 0; + det_edep_mup[nSignals] = 0; + G4String aParticleName = aHit->GetParticleName(); + if (aParticleName=="e-") { + det_edep_el[nSignals] += aHit->GetEdep(); + } else if (aParticleName=="e+") { + det_edep_pos[nSignals] += aHit->GetEdep(); + } else if (aParticleName=="gamma") { + det_edep_gam[nSignals] += aHit->GetEdep(); + } else if (aParticleName=="mu+") { + det_edep_mup[nSignals] += aHit->GetEdep(); + } else { + char message[200]; + sprintf(message,"musrScintSD.cc::EndOfEvent(): UNTREATED PARTICLE \"%s\" deposited energy.",aParticleName.c_str()); + musrErrorMessage::GetInstance()->musrError(WARNING,message,true); + } + G4ThreeVector prePos = aHit->GetPrePos(); + det_x[nSignals]=prePos.x(); + det_y[nSignals]=prePos.y(); + det_z[nSignals]=prePos.z(); + det_kine[nSignals] = aHit->GetKineticEnergy(); + det_VrtxKine[nSignals] = aHit->GetVertexKineticEnergy(); + G4ThreeVector VrtxPos = aHit->GetVertexPosition(); + det_VrtxX[nSignals] = VrtxPos.x(); + det_VrtxY[nSignals] = VrtxPos.y(); + det_VrtxZ[nSignals] = VrtxPos.z(); + G4String logicalVolumeAtVertex = aHit->GetLogicalVolumeAtVertex(); + det_VrtxVolID[nSignals] = myRootOutput->ConvertVolumeToID(logicalVolumeAtVertex); + G4String creatorProcessName = aHit->GetCreatorProcessName(); + det_VrtxProcID[nSignals] = myRootOutput->ConvertProcessToID(creatorProcessName); + det_VrtxTrackID[nSignals] = aHit->GetTrackID(); + det_VrtxParticleID[nSignals] = aHit->GetParticleID(); + det_VvvTrackSign[nSignals] = 1; + nSignals++; + } + } // end of "if (!signalAssigned)" + } // end of the for loop over the hits + + // Sort the signals according to the energy (in decreasing order) + std::map mySignalMapping; + std::map::iterator itt; + for (G4int i=0; i(-det_edep[i],i) ); + } + + // Write out the signals (sorted according to energy) to the musrRootOutput class: + G4int jj=-1; + for (itt=mySignalMapping.begin(); itt!=mySignalMapping.end(); itt++) { + jj++; + G4int ii = itt->second; + myRootOutput->SetDetectorInfo(jj,det_ID[ii],det_VrtxParticleID[ii],det_edep[ii], + det_edep_el[ii],det_edep_pos[ii], + det_edep_gam[ii],det_edep_mup[ii],det_nsteps[ii],det_length[ii], + det_time_start[ii],det_time_end[ii],det_x[ii],det_y[ii],det_z[ii], + det_kine[ii],det_VrtxKine[ii],det_VrtxX[ii],det_VrtxY[ii],det_VrtxZ[ii], + det_VrtxVolID[ii],det_VrtxProcID[ii],det_VrtxTrackID[ii] ); + + if (boolIsVvvInfoRequested) { + G4int oldTrackID = abs(det_VrtxTrackID[ii]); + musrSteppingAction* myMusrSteppingAction = musrSteppingAction::GetInstance(); + G4int vvvParentTrackID= -1; G4int vvvPparticleID; G4double vvvKine; G4ThreeVector vvvPosition; G4String vvvLogVol; G4String vvvProcess; + G4int vvvLogVolID=-999; + G4bool oldTrackRetrievedOK; + do { + if (vvvParentTrackID>-1) {oldTrackID=vvvParentTrackID;} + oldTrackRetrievedOK = myMusrSteppingAction->GetInfoAboutOldTrack(oldTrackID, + vvvParentTrackID, vvvPparticleID, vvvKine, vvvPosition, vvvLogVol, vvvProcess); + if (oldTrackRetrievedOK) { + // G4cout<<"musrScintSD: Old Track seems to be achieved fine -> Lets save it to Root tree"<ConvertVolumeToID(vvvLogVol); + } + else { + G4cout<<" oldTrackRetrievedOK is false"<ConvertProcessToID(vvvProcess); + myRootOutput->SetDetectorInfoVvv(jj,vvvKine,vvvPosition.x(),vvvPosition.y(),vvvPosition.z(), + vvvLogVolID,vvvProcessID,oldTrackID*det_VvvTrackSign[ii],vvvPparticleID); + } + } //end "boolIsVvvInfoRequested" + + } + } //end "if (NbHits>0)" + + myRootOutput->FillEvent(); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... diff --git a/src/musrSteppingAction.cc b/src/musrSteppingAction.cc new file mode 100644 index 0000000..fc52f0d --- /dev/null +++ b/src/musrSteppingAction.cc @@ -0,0 +1,443 @@ +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +#include "musrSteppingAction.hh" +#include "G4SteppingManager.hh" +#include "G4UnitsTable.hh" +#include "G4RunManager.hh" // needed for the event nr. comparison +#include "G4Run.hh" // ---------------||------------------ +#include "G4MagneticField.hh" // needed for storing the magnetic field to the Root class +#include "G4FieldManager.hh" // ---------------||------------------ +#include "G4TransportationManager.hh" // ---------------||------------------ +#include "musrErrorMessage.hh" +#include "musrParameters.hh" +#include "F04GlobalField.hh" + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +musrSteppingAction::musrSteppingAction() { + pointer=this; + + boolIsAnySpecialSaveVolumeDefined = false; + boolIsVvvInfoRequested = false; + boolMuonEventReweighting = false; + boolCalculateFieldIntegral = false; + myRootOutput = musrRootOutput::GetRootInstance(); + if (myRootOutput == NULL) { + musrErrorMessage::GetInstance()->musrError(FATAL, + "musrSteppingAction::musrSteppingAction(): pointer to the musrRootOutput class not found! ==> EXECUTION STOPPED",true); + } + lastActualVolume="Unset"; +} + +musrSteppingAction::~musrSteppingAction() { +} + + + musrSteppingAction* musrSteppingAction::pointer=0; + musrSteppingAction* musrSteppingAction::GetInstance() +{ + return pointer; +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... +void musrSteppingAction::DoAtTheBeginningOfEvent() { + // G4cout<<"musrSteppingAction::DoAtTheBeginningOfEvent: at the beginning"<GetTrack(); + + // suspend the track if too many steps has already happened (relevant at high field) + if (aTrack->GetCurrentStepNumber()>100000) { + musrErrorMessage::GetInstance()->musrError(WARNING, + "musrSteppingAction: Current number of steps for the track > 100000 ==> TRACK KILLED",true); + G4double x=aStep->GetPostStepPoint()->GetPosition().x()/mm; + G4double y=aStep->GetPostStepPoint()->GetPosition().y()/mm; + G4double z=aStep->GetPostStepPoint()->GetPosition().z()/mm; + G4double E=aTrack->GetVertexKineticEnergy()/MeV; + myRootOutput->htest1->Fill(x,y); + myRootOutput->htest2->Fill(sqrt(x*x+y*y),z); + myRootOutput->htest3->Fill(E); + aTrack->SetTrackStatus(fStopAndKill); + } + + // abort the event if it takes too long to finish (e.g. more than 60 seconds) + if ((time(0) - realTimeWhenThisEventStarted)>60) { + G4RunManager* fRunManager = G4RunManager::GetRunManager(); + G4cout<<"musrSteppingAction: event "<GetCurrentEvent()->GetEventID() + <<" aborted because calculation took already 60 seconds."<musrError(WARNING, + "musrSteppingAction: event aborted because its calculation takes more than 60 seconds.",true); + //delete musrRootOutput* myRootOutput = musrRootOutput::GetRootInstance(); + myRootOutput->SetEventWeight(0); + fRunManager->AbortEvent(); + } + + // Temporary fix to avoid crashes caused by particles with unphysically high energies + // (probably corrupted event?) + if ((aStep->GetPreStepPoint()->GetKineticEnergy()) > (1*GeV)) { + musrErrorMessage::GetInstance()->musrError(SERIOUS, + "musrSteppingAction: kinetic energy of a particle larger than 1GeV! STRANGE FOR muSR!",false); + G4RunManager* fRunManager = G4RunManager::GetRunManager(); + G4cout<<" Event nr.:"<GetCurrentEvent()->GetEventID() + <<", the particle \""<< aTrack->GetDynamicParticle()->GetDefinition()->GetParticleName() + <<"\" has energy of "<<(aStep->GetPreStepPoint()->GetKineticEnergy())/GeV<<" GeV."<SetEventWeight(0); + fRunManager->AbortEvent(); + } + + if (aTrack->GetDefinition()) { + G4ParticleDefinition* p_definition = aTrack->GetDynamicParticle()->GetDefinition(); + G4String p_name = p_definition->GetParticleName(); + // G4ProcessManager* p_manager = p_definition->GetProcessManager(); + G4LogicalVolume* actualLogicalVolume = aTrack->GetVolume()->GetLogicalVolume(); + G4String actualVolume = actualLogicalVolume->GetName(); + + // Delete track if the particle is in the "kill" volume. + // There is an example how to delete the track in example/novice/N04. + // It is done in a different way here, because the example/novice/N04 was not doing + // exactly what I wanted. + if((actualVolume(0,8)=="log_kill")||(actualVolume(0,8)=="log_Kill")) { + aTrack->SetTrackStatus(fStopAndKill); // suspend the track + } + if ((p_name=="nu_mu")||(p_name=="anti_nu_mu")||(p_name=="nu_e")||(p_name=="anti_nu_e")) { + //aTrack->SetTrackStatus(fStopAndKill); // suspend the tracks of neutrinos + } + + + // Save info about the old tracks, if the user wish to have Vvv info in the output Root Tree. + if (boolIsVvvInfoRequested) { + G4VPhysicalVolume* nextVolume = aTrack->GetNextVolume(); + if (nextVolume!=NULL) { + if ((nextVolume->GetLogicalVolume()->GetSensitiveDetector()!=NULL)||(actualLogicalVolume->GetSensitiveDetector()!=NULL)) { + G4int trackID = aTrack->GetTrackID(); + std::map::iterator itr; + itr = myOldTracksMap.find(trackID); + if (itr==myOldTracksMap.end()) { + // track with this trackID has not been found in the map (has not been saved yet) ==> save it + indexOfOldTrack++; + myOldTracksMap.insert( std::pair(trackID,indexOfOldTrack) ); + if (indexOfOldTrackGetDefinition()->GetPDGEncoding(); + parentTrackID_oldTrack[indexOfOldTrack] = aTrack->GetParentID(); + vertexKine_oldTrack[indexOfOldTrack] = aTrack->GetVertexKineticEnergy(); + vertexPosition_oldTrack[indexOfOldTrack] = aTrack->GetVertexPosition(); + vertexLogVol_oldTrack[indexOfOldTrack] = aTrack->GetLogicalVolumeAtVertex()->GetName(); + if ((aTrack->GetCreatorProcess())!=NULL) { vertexProcess_oldTrack[indexOfOldTrack] = aTrack->GetCreatorProcess()->GetProcessName();} + else { vertexProcess_oldTrack[indexOfOldTrack] = "initialParticle";} + } + else { + musrErrorMessage::GetInstance()->musrError(WARNING, + "musrSteppingAction: Maximum number of oldTracks reached ==> det_VvvXXX variables might be affected.",true); + } + } + } + } + } + + + // This are the data just for the radioactive decay (when using the radioactive source): + if ((musrParameters::boolG4GeneralParticleSource)) { + // &&(!radioactiveElectronAlreadySavedInThisEvent)) { + if (aTrack->GetTrackID() != 1 ){ + if (aTrack->GetCreatorProcess()->GetProcessName() == "RadioactiveDecay") { + if (aTrack->GetDefinition()->GetParticleName()=="e-") { + if (aTrack->GetCurrentStepNumber()==1) { + G4double electron_kinetic_energy=aStep->GetPreStepPoint()->GetKineticEnergy(); + myRootOutput->htest4->Fill(electron_kinetic_energy); + } + } + } + } + } + + + // Check if particle comes to the special volume + if (boolIsAnySpecialSaveVolumeDefined) { + // G4bool isFirstStepInVolume=aStep->IsFirstStepInVolume(); + // This does not work!!! (aStep->IsFirstStepInVolume() is always zero.) I do not understand why! + G4bool isFirstStepInVolume=false; + if (actualVolume!=lastActualVolume) { + lastActualVolume=actualVolume; + isFirstStepInVolume=true; + } + + if (isFirstStepInVolume) { + G4int tmpVolumeID=saveVolumeMapping[actualVolume]; + if (tmpVolumeID!=0) { + G4int particle_id_save=p_definition->GetPDGEncoding(); + G4double ke_save=aStep->GetPreStepPoint()->GetKineticEnergy(); + G4double x_save=aStep->GetPreStepPoint()->GetPosition().x(); + G4double y_save=aStep->GetPreStepPoint()->GetPosition().y(); + G4double z_save=aStep->GetPreStepPoint()->GetPosition().z(); + G4double px_save=aStep->GetPreStepPoint()->GetMomentum().x(); + G4double py_save=aStep->GetPreStepPoint()->GetMomentum().y(); + G4double pz_save=aStep->GetPreStepPoint()->GetMomentum().z(); + myRootOutput->SetSaveDetectorInfo(tmpVolumeID,particle_id_save,ke_save,x_save,y_save,z_save,px_save,py_save,pz_save); + } + } + } + + + if ((p_name == "mu+")||(p_name == "mu-")||(p_name == "Mu")) { + // Store the information about the muon when it enters the target, M0, M1 or M2 for the fist time + // in a given event (i.e. the code has to be called just once during the event). + if ((actualVolume=="log_target")||(actualVolume=="log_Target")) { + if (!muAlreadyWasInTargetInThisEvent) { + muAlreadyWasInTargetInThisEvent=true; + myRootOutput->SetPolInTarget(aTrack->GetPolarization()); + myRootOutput->SetTimeInTarget(aTrack->GetGlobalTime()); + } + } + else if ((actualVolume=="log_M0")||(actualVolume=="log_m0")) { + if (!muAlreadyWasInM0InThisEvent) { + muAlreadyWasInM0InThisEvent=true; + myRootOutput->SetPolInM0(aTrack->GetPolarization()); + myRootOutput->SetTimeInM0(aTrack->GetGlobalTime()); + } + } + else if ((actualVolume=="log_M1")||(actualVolume=="log_m1")) { + if (!muAlreadyWasInM1InThisEvent) { + muAlreadyWasInM1InThisEvent=true; + myRootOutput->SetPolInM1(aTrack->GetPolarization()); + myRootOutput->SetTimeInM1(aTrack->GetGlobalTime()); + } + } + else if ((actualVolume=="log_M2")||(actualVolume=="log_m2")) { + if (!muAlreadyWasInM2InThisEvent) { + muAlreadyWasInM2InThisEvent=true; + myRootOutput->SetPolInM2(aTrack->GetPolarization()); + myRootOutput->SetTimeInM2(aTrack->GetGlobalTime()); + } + } + + + // Calculate the field integral along the muon path, if requested by the user. + // (2008.10.20. - idea of Robert is to calculate the distribution of the field integral for different muon paths + // to see what (delta_I/I) is still acceptable for hith field muSR. To calculate it properly, the user must + // force Geant to use very small step size. + if (boolCalculateFieldIntegral) { + if (F04GlobalField::Exists()) { + G4ThreeVector position_tmp = aStep->GetPostStepPoint()->GetPosition(); + CoordinateForFieldIntegral[0] = position_tmp.x(); + CoordinateForFieldIntegral[1] = position_tmp.y(); + CoordinateForFieldIntegral[2] = position_tmp.z(); + CoordinateForFieldIntegral[3] = aTrack->GetGlobalTime(); + F04GlobalField::getObject() -> GetFieldValue(CoordinateForFieldIntegral,FieldForFieldIntegral); + G4double stepLength = aStep->GetStepLength(); + // BxIntegral += stepLength; + // ByIntegral += stepLength; + // BzIntegral += stepLength; + BxIntegral += stepLength * FieldForFieldIntegral[0]; + ByIntegral += stepLength * FieldForFieldIntegral[1]; + BzIntegral += stepLength * FieldForFieldIntegral[2]; + BzIntegral1 += ( position_tmp.z() - aStep->GetPreStepPoint()->GetPosition().z() ) * FieldForFieldIntegral[2]; + BzIntegral2 += stepLength; + BzIntegral3 += ( position_tmp.z() - aStep->GetPreStepPoint()->GetPosition().z() ); + // G4cout<<"BzIntegral="<GetPostStepPoint()->GetProcessDefinedStep(); + if (process!=NULL) { + G4String processName = process->GetProcessName(); + if (processName=="DecayWithSpin") { + // std::cout<<"musrSteppingAction: DecayWithSpin"<musrError(INFO, + "musrSteppingAction: event deleted because of the reweighting.",true); + G4RunManager* fRunManager = G4RunManager::GetRunManager(); + weight=0; + fRunManager->AbortEvent(); + } + // else { + // G4cout<<"Event will be reweighted"<SetEventWeight(weight); + } + } + + // Store the information about the decaying muon and store it in the Root tree + G4double timeOfDecay_tmp=aTrack->GetGlobalTime(); + G4ThreeVector positionOfDecay_tmp = aStep->GetPostStepPoint()->GetPosition(); + G4double BFieldAtOrigin[6] = {0.,0.,0.,0.,0.,0.}; + G4double PointOfDecay[4] ={positionOfDecay_tmp.x(),positionOfDecay_tmp.y(),positionOfDecay_tmp.z(),timeOfDecay_tmp}; + if (F04GlobalField::Exists()) { + F04GlobalField* myGlobalField = F04GlobalField::getObject(); + myGlobalField->GetFieldValue(PointOfDecay,BFieldAtOrigin); + } + else { + G4FieldManager *fMgr=G4TransportationManager::GetTransportationManager()->GetFieldManager(); + // G4cout<<"Debug 1"<DoesFieldChangeEnergy()) { //then we have a magnetic field + // G4cout<<"Debug 3"<GetDetectorField()->GetFieldValue(PointOfDecay,BFieldAtOrigin); + } + } + } + myRootOutput->SetDecayTime(timeOfDecay_tmp); + myRootOutput->SetDecayPolarisation(aTrack->GetPolarization()); + myRootOutput->SetDecayPosition(positionOfDecay_tmp); + myRootOutput->SetDecayDetectorID(actualVolume); + myRootOutput->SetBField(BFieldAtOrigin); + if (boolCalculateFieldIntegral) { + myRootOutput->SetBFieldIntegral(BxIntegral,ByIntegral,BzIntegral,BzIntegral1,BzIntegral2,BzIntegral3); + } + // G4cout<<"================================================== BzIntegral = "<GetSecondary(); + G4int n_secondaries= (*secondary).size(); + for (G4int i=0; iGetDefinition()->GetParticleName()) == "e+" ) { + myRootOutput->SetInitialPositronMomentum((*secondary)[i]->GetMomentum()); + } + } + } + } + + + // G4ThreeVector position = aStep->GetPostStepPoint()->GetPosition(); + // G4ThreeVector polarization=aTrack->GetDynamicParticle()->GetPolarization(); + } + + else { // particle is not muon + // Delete track if the particle is far away from the detector (i.e. in the "shield" volume). + // There is an example how to delete the track in example/novice/N04. + // It is done in a different way here, because the example/novice/N04 was not doing + // exactly what I wanted. + if ( ((musrParameters::killAllPositrons)&&(p_name == "e+")) || + ((musrParameters::killAllGammas)&&(p_name == "gamma")) || + ((musrParameters::killAllNeutrinos)&&((p_name == "nu_mu")||(p_name == "anti_nu_mu")||(p_name == "nu_e")||(p_name == "anti_nu_e"))) ){ + aTrack->SetTrackStatus(fStopAndKill); // suspend the track + } + if((actualVolume(0,10)=="log_shield")||(actualVolume(0,10)=="log_Shield")) { + aTrack->SetTrackStatus(fStopAndKill); // suspend the track + } + } + } +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + + +void musrSteppingAction::SetLogicalVolumeAsSpecialSaveVolume(G4String logicName, G4int volumeID) { + boolIsAnySpecialSaveVolumeDefined = true; + saveVolumeMapping[logicName]=volumeID; +} + + +void musrSteppingAction::SetVolumeForMuonEventReweighting(G4String logicName, G4int weight) { + boolMuonEventReweighting = true; + volumeMuonWeightMapping[logicName]=weight; +} + +G4bool musrSteppingAction::GetInfoAboutOldTrack(G4int trackID, G4int& parentTrackID, G4int& particleID, G4double& vertexKine, + G4ThreeVector& vertexPosition, G4String& vertexLogVol, G4String& vertexProcess) { + // G4int ind = myOldTracksMap[trackID]; + // G4cout<<"musrSteppingAction::GetInfoAboutOldTrack: trackID="<musrError(WARNING,eMessage,false); + G4cout<<" Requested trackID="<maxNumberOfOldTracks! ("<"<first = "<first<<", trackID = "<::iterator itr; + G4int ind; + + G4int track1; + G4int trID = trackID1; + do { + track1=trID; + itr = myOldTracksMap.find(trID); + if ( itr==myOldTracksMap.end() ) { + G4cout<<"musrSteppingAction::AreTracksCommingFromSameParent() Strange, trackID1 ="<second; + trID = parentTrackID_oldTrack[ind]; + } while (vertexLogVol_oldTrack[ind]==volumeName); + + G4int track2; + trID = trackID2; + do { + track2=trID; + itr = myOldTracksMap.find(trID); + if ( itr==myOldTracksMap.end() ) { + G4cout<<"musrSteppingAction::AreTracksCommingFromSameParent() Strange, trackID2 ="<second; + trID = parentTrackID_oldTrack[ind]; + } while (vertexLogVol_oldTrack[ind]==volumeName); + + + if (track1==track2) {return true;} + //G4cout<<"track1="<= 1 ){ + if( verboseLevel >= 4 ) VerboseTrack(); + if( verboseLevel >= 3 ){ + G4cout << G4endl; + G4cout << std::setw( 5) << "#Step#" << " " + << std::setw( 6) << "X" << " " + << std::setw( 6) << "Y" << " " + << std::setw( 6) << "Z" << " " + << std::setw( 9) << "KineE" << " " + << std::setw( 9) << "dEStep" << " " + << std::setw(10) << "StepLeng" + << std::setw(10) << "TrakLeng" + << std::setw(10) << "Volume" << " " + << std::setw(10) << "Process" << G4endl; + } + + G4cout << std::setw(5) << fTrack->GetCurrentStepNumber() << " " + << std::setw(6) << G4BestUnit(fTrack->GetPosition().x(),"Length") + << std::setw(6) << G4BestUnit(fTrack->GetPosition().y(),"Length") + << std::setw(6) << G4BestUnit(fTrack->GetPosition().z(),"Length") + << std::setw(6) << G4BestUnit(fTrack->GetKineticEnergy(),"Energy") + << std::setw(6) << G4BestUnit(fStep->GetTotalEnergyDeposit(),"Energy") + << std::setw(6) << G4BestUnit(fStep->GetStepLength(),"Length") + << std::setw(6) << G4BestUnit(fTrack->GetTrackLength(),"Length") + << " "; + + // if( fStepStatus != fWorldBoundary){ + if( fTrack->GetNextVolume() != 0 ) { + G4cout << std::setw(10) << fTrack->GetVolume()->GetName(); + } else { + G4cout << std::setw(10) << "OutOfWorld"; + } + + if(fStep->GetPostStepPoint()->GetProcessDefinedStep() != NULL){ + G4cout << " " + << std::setw(10) << fStep->GetPostStepPoint()->GetProcessDefinedStep() + ->GetProcessName(); + } else { + G4cout << " UserLimit"; + } + + G4cout << G4endl; + + if( verboseLevel == 2 ){ + G4int tN2ndariesTot = fN2ndariesAtRestDoIt + + fN2ndariesAlongStepDoIt + + fN2ndariesPostStepDoIt; + if(tN2ndariesTot>0){ + G4cout << " :----- List of 2ndaries - " + << "#SpawnInStep=" << std::setw(3) << tN2ndariesTot + << "(Rest=" << std::setw(2) << fN2ndariesAtRestDoIt + << ",Along=" << std::setw(2) << fN2ndariesAlongStepDoIt + << ",Post=" << std::setw(2) << fN2ndariesPostStepDoIt + << "), " + << "#SpawnTotal=" << std::setw(3) << (*fSecondary).size() + << " ---------------" + << G4endl; + + for(size_t lp1=(*fSecondary).size()-tN2ndariesTot; + lp1<(*fSecondary).size(); lp1++){ + G4cout << " : " + << std::setw(6) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x(),"Length") + << std::setw(6) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y(),"Length") + << std::setw(6) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z(),"Length") + << std::setw(6) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy(),"Energy") + << std::setw(10) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName(); + G4cout << G4endl; + } + + G4cout << " :-----------------------------" + << "----------------------------------" + << "-- EndOf2ndaries Info ---------------" + << G4endl; + } + } + + } + G4cout.precision(prec); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... + +void musrSteppingVerbose::TrackingStarted() +{ + + CopyState(); +G4int prec = G4cout.precision(3); + if( verboseLevel > 0 ){ + + G4cout << std::setw( 5) << "Step#" << " " + << std::setw( 6) << "X" << " " + << std::setw( 6) << "Y" << " " + << std::setw( 6) << "Z" << " " + << std::setw( 9) << "KineE" << " " + << std::setw( 9) << "dEStep" << " " + << std::setw(10) << "StepLeng" + << std::setw(10) << "TrakLeng" + << std::setw(10) << "Volume" << " " + << std::setw(10) << "Process" << G4endl; + + G4cout << std::setw(5) << fTrack->GetCurrentStepNumber() << " " + << std::setw(6) << G4BestUnit(fTrack->GetPosition().x(),"Length") + << std::setw(6) << G4BestUnit(fTrack->GetPosition().y(),"Length") + << std::setw(6) << G4BestUnit(fTrack->GetPosition().z(),"Length") + << std::setw(6) << G4BestUnit(fTrack->GetKineticEnergy(),"Energy") + << std::setw(6) << G4BestUnit(fStep->GetTotalEnergyDeposit(),"Energy") + << std::setw(6) << G4BestUnit(fStep->GetStepLength(),"Length") + << std::setw(6) << G4BestUnit(fTrack->GetTrackLength(),"Length") + << " "; + + if(fTrack->GetNextVolume()){ + G4cout << std::setw(10) << fTrack->GetVolume()->GetName(); + } else { + G4cout << std::setw(10) << "OutOfWorld"; + } + G4cout << " initStep" << G4endl; + } + G4cout.precision(prec); +} + +//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... diff --git a/src/musrTabulatedElementField.cc b/src/musrTabulatedElementField.cc new file mode 100644 index 0000000..582cdcf --- /dev/null +++ b/src/musrTabulatedElementField.cc @@ -0,0 +1,596 @@ +#include "musrTabulatedElementField.hh" +#include "musrParameters.hh" +#include "musrErrorMessage.hh" +#include "G4UnitsTable.hh" + +musrTabulatedElementField::musrTabulatedElementField( const char* filename, const char* fldTableType, G4double fieldValue, G4LogicalVolume* logVolume, G4ThreeVector positionOfTheCenter) : F04ElementField(positionOfTheCenter, logVolume), + ffieldValue(fieldValue) +{ + // The following posibilities of the format of the field map are distinguieshed: + // 3DBOpera = 3D ... 3D field , magnetic, Opera format (Kamil-like) + // 3DE ... 3D field , electric, Toni-like (3DE WAS TESTED) + // 3DB ... 3D field , magnetic, Toni-like + // 2DBOpera = 2D .... 2D field, magnetic, Opera format (Kamil-like), X and Z components (2D WAS TESTED) + // 2DBOperaXY = 2D_OperaXY .... 2D field, magnetic, Opera format with (Kamil-like), X and Y components + // 2DE ... 2D field , electric, Toni-like (2DE WAS TESTED) + // 2DB ... 2D field , magnetic, Toni-like + + G4double lenUnit = 1*m; // length unit of the field map grid coordinates + G4double fieldNormalisation = 1.; // Normalisation factor by which the the field map has to be multiplied + // in order to get 1T (in the case of magnetic field) + // "lenUnit" and "fieldNormalisation" are needed only if not specified + // inside the fieldmap file; + strcpy(fieldTableType,fldTableType); + fldType = 'B'; + fUnit = "T"; + fieUnit = tesla; + if (fieldTableType[2]=='E') { + fldType = 'E'; + fUnit = "kV/mm"; + fieUnit= kilovolt/mm; + } + + fldDim = (fieldTableType[0]=='3') ? 3:2; + if (fldDim==2) ny=1; + + G4cout << "\n-----------------------------------------------------------" << G4endl; + G4cout << " Field (of type "< " "Reading the field grid from " << filename << " ... " << G4endl; + std::ifstream file( filename ); // Open the file for reading. + if (!(file.is_open())) { + G4cout << "Fieldmap file \""<< filename << "\" not opened (found) !!!"<musrError(FATAL,"musrTabulatedElementField: Field map file not found !",false); + } + + char buffer[256]; + G4bool boolMinimaAndMaximaDefinedInTheFile = false; + if (fldType=='E') G4cout<<" Electric field "; + if (fldType=='B') G4cout<<" Magnetic field "; + if ((strcmp(fieldTableType,"3DE")==0)||(strcmp(fieldTableType,"3DB")==0)) { + // File is in Toni Shiroka format: + // Read the number of arguments and decide filetype - 3 or 6 columns + G4cout << "3D, field-map file format by Toni Shiroka" << G4endl; + char lenUnitFromFile[50]; + double fieldNormalisationFromFile; + file.getline(buffer,256); + int n_arg = sscanf (buffer,"%d %d %d %s %lf %lf %lf %lf %lf %lf %lf", + &nx, &ny, &nz, lenUnitFromFile, &fieldNormalisationFromFile, + &minimumx, &maximumx, &minimumy, &maximumy, &minimumz, &maximumz); + lenUnit = G4UnitDefinition::GetValueOf(lenUnitFromFile); + fieldNormalisation = fieldNormalisationFromFile; + if (n_arg==11) { + // The length unit and norm. factor have to be manually added to the field-map file! + G4cout << " ---> Assumed order (3 col.): "< Assumed order (6 col.): x, y, z, "< Assumed order (7 col.): x, y, z, "<> nx >> ny >> nz; // Note dodgy order + + // Ignore other header information + // The first line whose second character is '0' is considered to + // be the last line of the header. + do { + file.getline(buffer,256); + } while ( buffer[1]!='0'); + } + else if ((strcmp(fieldTableType,"2DE")==0)||(strcmp(fieldTableType,"2DB")==0)||(strcmp(fieldTableType,"2DEf")==0)) { + // File is in Toni Shiroka format: + G4cout << "2D, field-map file format by Toni Shiroka" << G4endl; + G4cout << " ---> Assumed order (4 col.): r, z, "<> nx >> nz >> lenUnitFromFile >> fieldNormalisation; + lenUnit = G4UnitDefinition::GetValueOf(lenUnitFromFile); + // Ignore header information. All lines whose first character + // is '%' are considered to be part of the header. + do { + file.ignore(256, '\n'); + } while (file.peek() == '%'); + } + else if ((strcmp(fieldTableType,"2D_OperaXY")==0)||(strcmp(fieldTableType,"2DBOperaXY")==0)) { + int nDummy; + lenUnit = 1*cm; + fieldNormalisation = 0.00001; + G4cout << "2D, field-map file format from OPERA with X,Y components (Kamil)" << G4endl; + G4cout << " ---> Assumed order (6 col.): r, z, dummy, "<> nx >> nz >> nDummy; + do { + file.getline(buffer,256); + } while ( buffer[1]!='0'); + } + else if ((strcmp(fieldTableType,"2D")==0)||(strcmp(fieldTableType,"2DBOpera")==0)) { + int nDummy; + lenUnit = 1*cm; + fieldNormalisation = 0.00001; + G4cout << "2D, field-map file format from OPERA with X,Z components (Kamil)" << G4endl; + G4cout << " ---> Assumed order (6 col.): r, dummy, z, "<> nx >> nDummy >> nz; + // G4cout << nx <<" "<< nDummy <<" "<< nz< S T O P " << G4endl; + musrErrorMessage::GetInstance()->musrError(FATAL,"musrTabulatedElementField: Unknown field required!",false); + } + + + + // SET UP STORAGE SPACE FOR THE TABLE + int ix, iy, iz; + if (fldDim==3) { + G4cout << " The grid consists of [" << nx << " x " << ny << " x " << nz << "] x, y, z values" << G4endl; + G4cout << " Field map length unit = " << lenUnit/mm<<" mm"<< G4endl; + G4cout << " Field map normalisation factor = " << fieldNormalisation << G4endl; + // Set up storage space for the table + xField.resize( nx ); + yField.resize( nx ); + zField.resize( nx ); + for (ix=0; ixmusrError(WARNING,eMessage,false); + } + // Set up storage space for the table + xField2D.resize( nx ); + zField2D.resize( nx ); + for (ix=0; ix> bx >> by >> bz; // Read ONLY field values + } + else { + file >> xval >> yval >> zval >> bx >> by >> bz; + } + } + else if ((strcmp(fieldTableType,"3D")==0)||(strcmp(fieldTableType,"3DBOpera")==0)) { + file >> xval >> yval >> zval >> bx >> by >> bz >> permeability; + } + else if ((strcmp(fieldTableType,"2DE")==0)||(strcmp(fieldTableType,"2DB")==0)||(strcmp(fieldTableType,"2DEf")==0)) { + file >> xval >> zval >> bx >> bz; + } + else if ((strcmp(fieldTableType,"2D")==0)||(strcmp(fieldTableType,"2DBOpera")==0)) { + file >> xval >> yval >> zval >> bx >> bz >> permeability; + // G4cout<< xval <<" "<< yval <<" "<< zval <<" "<< bx <<" "<< bz <> xval >> zval >> yval >> bx >> bz >> permeability; + } + else { + G4cout << " musrTabulatedElementField::musrTabulatedElementField: Undefined field required!" + << " ("< S T O P " << G4endl; + musrErrorMessage::GetInstance()->musrError(FATAL,"musrTabulatedElementField: Undefined field required!",false); + } + + + if (fldDim==3) { // 3D field + if ((!boolMinimaAndMaximaDefinedInTheFile) && ( ix==0 && iy==0 && iz==0 ) ) { + minimumx = xval * lenUnit; + minimumy = yval * lenUnit; + minimumz = zval * lenUnit; + } + xField[ix][iy][iz] = bx*fieldNormalisation; + yField[ix][iy][iz] = by*fieldNormalisation; + zField[ix][iy][iz] = bz*fieldNormalisation; + } + else { // 2D field + if ((!boolMinimaAndMaximaDefinedInTheFile) && ( ix==0 && iz==0 ) ) { + minimumx = xval * lenUnit; + minimumz = zval * lenUnit; + } + xField2D[ix][iz] = bx*fieldNormalisation; + zField2D[ix][iz] = bz*fieldNormalisation; + } + } + } + } + file.close(); + + + if (!boolMinimaAndMaximaDefinedInTheFile) { + maximumx = xval * lenUnit; + maximumz = zval * lenUnit; + if (fldDim==3) maximumy = yval * lenUnit; + } + + G4cout << " ---> ... reading of the field map finished." << G4endl; + + if (fldDim==3) G4cout<<" ---> Min values of x,y,z: "; + else G4cout<<" ---> Min values of R,z: "; + G4cout << minimumx/cm << ", "; + if (fldDim==3) G4cout<< minimumy/cm << ", " ; + G4cout << minimumz/cm << " cm "< Max values of x,y,z: "; + else G4cout<<" ---> Max values of R,z: "; + G4cout << maximumx/cm << ", "; + if (fldDim==3) G4cout<< maximumy/cm << ", " ; + G4cout << maximumz/cm << " cm " << G4endl; + + + // Should really check that the limits are not the wrong way around. + G4bool reorderingDone = false; + if (maximumx < minimumx) {Invert("x"); reorderingDone=true;} + if (fldDim==3) {if (maximumy < minimumy) {Invert("y"); reorderingDone=true;} } + if (maximumz < minimumz) {Invert("z"); reorderingDone=true;} + + if (reorderingDone) { + G4cout << "\n Reordering of the field grid was neccessary - after reordering:"< Min values of x,y,z: "; + else G4cout<<" ---> Min values of R,z: "; + G4cout << minimumx/cm << ", "; + if (fldDim==3) G4cout<< minimumy/cm << ", " ; + G4cout << minimumz/cm << " cm "< Max values of x,y,z: "; + else G4cout<<" ---> Max values of R,z: "; + G4cout << maximumx/cm << ", "; + if (fldDim==3) G4cout<< maximumy/cm << ", " ; + G4cout << maximumz/cm << " cm " << G4endl; + } + + dx = maximumx - minimumx; + if (fldDim==3) dy = maximumy - minimumy; + dz = maximumz - minimumz; + if (fldDim==3) G4cout << "\n ---> Dif values x,y,z (range): "; + else G4cout << "\n ---> Dif values R,z (range): "; + G4cout << dx/cm << ", "; + if (fldDim==3) G4cout << dy/cm << ", "; + G4cout << dz/cm << " cm."<minimumx && xminimumy && yminimumz && z(xdindex); + int yindex = static_cast(ydindex); + int zindex = static_cast(zdindex); + + //cks The following check is necessary - even though xindex and zindex should never be out of range, + // it may happen (due to some rounding error ?). It is better to leave the check here. + if ((xindex<0)||(xindex>(nx-2))) { + std::cout<<"SERIOUS PROBLEM: xindex out of range! xindex="<0) ? 1.:-1.; + } + else { + // Field is defined along the whole range of the z axis (i.e. asymmetric field is expected) + x = sqrt(local.x()*local.x()+local.y()*local.y()); + z = local.z(); + z_sign = 1; + } + // Check that the point is within the defined region + if ( xevNrKriz) std::cout<<"bol som tu"<(xdindex); + int zindex = static_cast(zdindex); + + //cks The following check is necessary - even though xindex and zindex should never be out of range, + // it may happen (due to some rounding error ?). It is better to leave the check here. + if ((xindex<0)||(xindex>(nx-2))) { + std::cout<<"SERIOUS PROBLEM: xindex out of range! xindex="< > > xFieldTemp(xField); + std::vector< std::vector< std::vector< double > > > yFieldTemp(yField); + std::vector< std::vector< std::vector< double > > > zFieldTemp(zField); + G4bool invertX=false; + G4bool invertY=false; + G4bool invertZ=false; + + G4cout<<"Check that the musrTabulatedElementField::Invert() function works properly!"<GetName().substr(4); + G4cout << "\n ---> EM field in volume " << volName << " set to:" << G4endl; + printf (" B = (%0.3g, %0.3g, %0.3g) T, E = (%0.3g, %0.3g, %0.3g) kV/mm\n", + EMF[0]/tesla, EMF[1]/tesla, EMF[2]/tesla, + EMF[3]/(kilovolt/mm), EMF[4]/(kilovolt/mm), EMF[5]/(kilovolt/mm)); + G4cout << "-----------------------------------------------------------" << G4endl; +} + + + +void musrUniformField::addFieldValue(const G4double point[4], + G4double field[6]) const +{ + G4ThreeVector global(point[0],point[1],point[2]); + G4ThreeVector local; + + local = global2local.TransformPoint(global); + + if (isOutside(local)) return; + + G4ThreeVector B(EMfield[0],EMfield[1],EMfield[2]); + G4ThreeVector E(EMfield[3],EMfield[4],EMfield[5]); + + B = global2local.Inverse().TransformAxis(B); + E = global2local.Inverse().TransformAxis(E); + + field[0] += B[0]; + field[1] += B[1]; + field[2] += B[2]; + + field[3] += E[0]; + field[4] += E[1]; + field[5] += E[2]; + + //printf (" EM field components: B = (%0.3g, %0.3g, %0.3g) T, E = (%0.3g, %0.3g, %0.3g) kV/mm\n", + //field[0]/tesla, field[1]/tesla, field[2]/tesla, + //field[3]/(kilovolt/mm), field[4]/(kilovolt/mm), field[5]/(kilovolt/mm)); +} + + + +G4double musrUniformField::GetNominalFieldValue() { + G4double val = std::sqrt(EMfield[0]*EMfield[0]+EMfield[1]*EMfield[1]+EMfield[2]*EMfield[2]+ + EMfield[3]*EMfield[3]+EMfield[4]*EMfield[4]+EMfield[5]*EMfield[5]); + return val; +} + +void musrUniformField::SetNominalFieldValue(G4double newFieldValue){ + EMfield[0] *= newFieldValue; + EMfield[1] *= newFieldValue; + EMfield[2] *= newFieldValue; + EMfield[3] *= newFieldValue; + EMfield[4] *= newFieldValue; + EMfield[5] *= newFieldValue; +} + +G4bool musrUniformField::isOutside(G4ThreeVector& local) const +{ + return (std::fabs(local.z()) > fieldLength/2.0 || std::fabs(local.x()) > fieldWidth/2.0 || std::fabs(local.y()) > fieldHeight/2.0); +} + +G4bool musrUniformField::isWithin(G4ThreeVector& local) const +{ + return (std::fabs(local.z()) < fieldLength/2.0 && std::fabs(local.x()) < fieldWidth/2.0 && std::fabs(local.y()) < fieldHeight/2.0); +} diff --git a/src/yields.cc b/src/yields.cc new file mode 100644 index 0000000..637282d --- /dev/null +++ b/src/yields.cc @@ -0,0 +1,107 @@ +// Geant4 simulation for MuSR +// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI +// DATE : 2008-05 +// + +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +// Muonium yields as a function of initial mu+ energies. +// The method GetYields is used by MuFormation. +// Id : yields.cc, v 1.1 +// Author: Taofiq PARAISO, T. Shiroka +// Date : 2007-12 +// Notes : First implemented in Fortran by A. Hofer +// C++ conversion by T.K. Paraiso 04-2005 +// Slight modifications by T. Shiroka +//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + +#include "yields.hh" + +#include +#include +#include +#include + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + The Muonium Yield function as well as the parameters are taken from: + M. Gonin, R. Kallenbach, P. Bochsler: "Charge exchange of hydrogen atoms + in carbon foils at 0.4 - 120 keV", Rev.Sci.Instrum. 65 (3), March 1994 +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +Yields:: Yields(){;} +Yields::~Yields(){;} + +void Yields::GetYields( + double E, // kinetic energy in keV + double mass, // mass in keV/c**2 + double yvector[3]) // pointer to the yields table + +{ + // Parameter NAMES for the muonium yield function + double a_zero, a_minus; + double k_Fermi, k_zero, k_minus; + double two_k_Fermi; + double k_Fermi_Quad, k_zero_Quad, k_minus_Quad; + double vc_minus, vc_plus, v_Bohr, v_rel; + + // Parameter VALUES for the muonium yield function + a_zero = 0.953; + a_minus = 0.029; + k_Fermi = 1.178; // [v_Bohr] + k_Fermi_Quad = k_Fermi * k_Fermi; + two_k_Fermi = 2. * k_Fermi; + k_zero = 0.991*k_Fermi; // [v_Bohr] + k_zero_Quad = k_zero * k_zero; + k_minus = 0.989*k_Fermi; // [v_Bohr] + k_minus_Quad = k_minus * k_minus; + vc_minus = 0.284; + vc_plus = 0.193; // [v_Bohr] + v_Bohr = 7.2974E-3; // [c] + + + // std::cout<<"E = "<< E < ABORTED!" < exp(-vc_minus/v_rel)) Yield_minus=exp(-vc_minus/v_rel); + if(Yield_plus > exp(-vc_plus/v_rel)) Yield_plus=exp(-vc_plus/v_rel); + + Yield_zero = 1. - (Yield_minus + Yield_plus); + + yvector[0]=Yield_plus; + yvector[1]=Yield_zero; + yvector[2]=Yield_minus; + + // std::cout<<"Y+ : "<< Yield_plus << std::endl; + // std::cout<<"Y0 : "<< Yield_zero << std::endl; +}