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.
This commit is contained in:
sedlak 2009-05-18 09:59:52 +00:00
commit fcd5eea567
66 changed files with 13320 additions and 0 deletions

36
GNUmakefile Normal file
View File

@ -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

45
doc/README_notes.txt Normal file
View File

@ -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"'
===========================================================================

View File

@ -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").

518
doc/dis04.cls Normal file
View File

@ -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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

BIN
doc/musrSim.pdf Normal file

Binary file not shown.

469
doc/musrSim.tex Normal file
View File

@ -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}

160
include/BLEngeFunction.hh Normal file
View File

@ -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 <math.h>
/** 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

171
include/F04ElementField.hh Normal file
View File

@ -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<G4int,G4double> 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<G4int,G4double> changeFieldInStepsMap;
};
#endif

View File

@ -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

195
include/F04GlobalField.hh Normal file
View File

@ -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 <vector>
#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<F04ElementField*> 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 "<<minStep/mm<<" mm."<<G4endl; }
/// Set the delta chord length
void SetDeltaChord(G4double s) { deltaChord = s; }
/// Set the delta one step length
void SetDeltaOneStep(G4double s) { deltaOneStep = s; }
/// Set the delta intersection length
void SetDeltaIntersection(G4double s) { deltaIntersection = s; }
/// Set the minimum eps length
void SetEpsMin(G4double s) { epsMin = s; }
/// Set the maximum eps length
void SetEpsMax(G4double s) { epsMax = s; }
/// Return the list of Element Fields
FieldList* getFields() { return fields; }
// G4bool DoesAnyFieldValueNeedsToBeChanged(G4int eventNumber) {return globalChangeFieldInStepsMap[eventNumber];}
void CheckWhetherAnyNominalFieldValueNeedsToBeChanged(G4int eventNumber);
// Add point, at which user wishes to print out the field value
void AddPointForFieldTesting(G4ThreeVector point) {pointsAtWhichUserWantsToPrintFieldValue.push_back(point);}
// Print field value at all points user wished to be print out:
void PrintFieldAtRequestedPoints() const;
protected:
/// Get the global field manager
G4FieldManager* GetGlobalFieldManager();
private:
static F04GlobalField* object;
G4int nfp;
G4bool first;
FieldList* fields;
const F04ElementField **fp;
std::vector<G4ThreeVector> 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<G4int,G4bool> globalChangeFieldInStepsMap;
};
#endif

71
include/MuDecayChannel.hh Normal file
View File

@ -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

View File

@ -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

70
include/meyer.hh Normal file
View File

@ -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 <iomanip>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <ios>
#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

View File

@ -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 <map>
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<std::string,G4RotationMatrix*> pointerToRotationMatrix;
std::map<std::string,G4FieldManager*> pointerToField;
private:
void DefineMaterials();
};
#endif

View File

@ -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

View File

@ -0,0 +1,29 @@
#ifndef musrErrorMessage_h
#define musrErrorMessage_h 1
#include <map>
#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<G4String,int> ErrorMapping;
std::map<G4String,ErrorStruct> ErrorMapping;
std::map<SEVERITY,G4String> severityWord;
};
#endif

View File

@ -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

View File

@ -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

57
include/musrMuScatter.hh Normal file
View File

@ -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

77
include/musrMuonium.hh Normal file
View File

@ -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

44
include/musrParameters.hh Normal file
View File

@ -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

View File

@ -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

View File

@ -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 <stdio.h>
#include <vector>
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 ("<<val<<")"<<G4endl;
exit(1);
}
polarisFraction=val;
}
void SetMuonDecayTimeLimits(G4ThreeVector decayTimeLimits);
void SetTurtleInput(G4String turtleFileName);
void SetTurtleInputFileToEventNo(G4int lineNumberOfTurtleFile);
void SetTurtleZ0(G4double val) {z0_InitialTurtle=val;}
void SetOrReadTheRandomNumberSeeds(G4int eventID);
void SetTurtleMomentumBite (G4ThreeVector smearingParam)
{turtleMomentumBite=true; turtleMomentumP0=smearingParam[0]*MeV; turtleSmearingFactor=smearingParam[1]*0.01;}
static G4String GetPrimaryName();
private:
G4ParticleGun* particleGun; // pointer a to G4 service class
G4GeneralParticleSource* particleSource; // pointer to the G4GeneralParticleSource, needed for radioactive samples
musrDetectorConstruction* musrDetector; // pointer to the geometry
musrPrimaryGeneratorMessenger* gunMessenger; // messenger of this class
G4String rndmFlag; // flag for a random impact point
// cks Implement also alpha and proton particles for the simulation of Juan Pablo Urrego
G4ParticleDefinition* alphaParticle;
G4ParticleDefinition* protonParticle;
// csk
static G4String thePrimaryParticleName ;
G4double x0, y0, z0, xSigma, ySigma, zSigma, rMaxAllowed, zMinAllowed, zMaxAllowed;
G4double p0, pSigma, pMinAllowed, pMaxAllowed;
G4double xangle0, yangle0, xangleSigma, yangleSigma, pitch;
G4bool UnpolarisedMuonBeam, TransversalyUnpolarisedMuonBeam;
G4double xPolarisIni, yPolarisIni, zPolarisIni;
G4double polarisFraction;
G4double muonDecayTimeMin;
G4double muonDecayTimeMax;
G4double muonMeanLife;
// For the Turtle input:
FILE* fTurtleFile;
G4bool takeMuonsFromTurtleFile;
G4double z0_InitialTurtle; // z0 at whith the turtle file was generated.
G4int numberOfGeneratedEvents; // number of generated events at the input (e.g. including Turtle events out of the beampipe)
G4bool boolPrintInfoAboutGeneratedParticles;
G4bool turtleMomentumBite;
G4double turtleMomentumP0;
G4double turtleSmearingFactor;
public:
static G4bool setRandomNrSeedAccordingEventNr;
static G4bool setRandomNrSeedFromFile;
static G4bool setRandomNrSeedFromFile_RNDM;
static G4int nRndmEventToSaveSeeds;
static std::vector<int> * GetPointerToSeedVector();
G4double decaytime;
private:
static std::vector<int> * pointerToSeedVector;
};
#endif

View File

@ -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

49
include/musrQuadrupole.hh Normal file
View File

@ -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 <fstream>
//#include <vector>
//#include <cmath>
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

291
include/musrRootOutput.hh Normal file
View File

@ -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 <map>
//....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="<<muIniPosX_t<<", y="<<muIniPosY_t<<", z="<<muIniPosZ_t
<<", px="<<muIniMomX_t << ", py="<<muIniMomY_t<<", pz="<<muIniMomZ_t<<G4endl;
G4cout<<" polx="<<muIniPolX_t<<", poly="<<muIniPolY_t<<", polz="<<muIniPolZ_t<<G4endl;
G4cout<<" numberOfGeneratedEvents = "<<GeantParametersD[7]<<G4endl;
}
void SetPolInTarget(G4ThreeVector pol) {muTargetPolX_t=pol.x(); muTargetPolY_t=pol.y(); muTargetPolZ_t=pol.z();};
void SetTimeInTarget(G4double time) {muTargetTime_t = time/microsecond;};
void SetPolInM0(G4ThreeVector pol) {muM0PolX_t=pol.x(); muM0PolY_t=pol.y(); muM0PolZ_t=pol.z();};
void SetTimeInM0(G4double time) {muM0Time_t = time/microsecond;};
void SetPolInM1(G4ThreeVector pol) {muM1PolX_t=pol.x(); muM1PolY_t=pol.y(); muM1PolZ_t=pol.z();};
void SetTimeInM1(G4double time) {muM1Time_t = time/microsecond;};
void SetPolInM2(G4ThreeVector pol) {muM2PolX_t=pol.x(); muM2PolY_t=pol.y(); muM2PolZ_t=pol.z();};
void SetTimeInM2(G4double time) {muM2Time_t = time/microsecond;};
void SetInitialPositronMomentum(G4ThreeVector mom) {posIniMomx_t=mom.x(); posIniMomy_t=mom.y(); posIniMomz_t=mom.z();};
void SetDecayTime(G4double time) {muDecayTime_t=time/microsecond;};
void SetNrFieldNomVal(G4int n) {nFieldNomVal = n;}
void SetFieldNomVal(G4int i, G4double value);
G4int GetNrOfVolumes() {return det_nMax;}
void SetBFieldIntegral(G4double BxInt,G4double ByInt,G4double BzInt,G4double BzInt1,G4double BzInt2,G4double BzInt3) {
BxIntegral_t=BxInt/m/tesla; ByIntegral_t=ByInt/m/tesla; BzIntegral_t=BzInt/m/tesla;
BzIntegral1_t=BzInt1/m/tesla;BzIntegral2_t=BzInt2/mm;BzIntegral3_t=BzInt3/mm;
}
void StoreGeantParameter(Int_t i, Double_t value) {
if (i<maxNGeantParameters) { GeantParametersD[i]=value; }
else {G4cout<<"musrRootOutput.hh::StoreGeantParameter: index="<<i<<" out of range"
<<" (maxNGeantParameters=" <<maxNGeantParameters<<")"<<G4endl;}
};
TH2F *htest1, *htest2;
TH1F *htest3, *htest4, *htest5, *htest6, *htest7, *htest8;
public:
static G4bool store_runID;
static G4bool store_eventID;
static G4bool store_weight;
static G4bool store_BFieldAtDecay;
static G4bool store_muIniPosX;
static G4bool store_muIniPosY;
static G4bool store_muIniPosZ;
static G4bool store_muIniMomX;
static G4bool store_muIniMomY;
static G4bool store_muIniMomZ;
static G4bool store_muIniPolX;
static G4bool store_muIniPolY;
static G4bool store_muIniPolZ;
static G4bool store_muDecayDetID;
static G4bool store_muDecayPosX;
static G4bool store_muDecayPosY;
static G4bool store_muDecayPosZ;
static G4bool store_muDecayTime;
static G4bool store_muDecayPolX;
static G4bool store_muDecayPolY;
static G4bool store_muDecayPolZ;
static G4bool store_muTargetTime;
static G4bool store_muTargetPolX;
static G4bool store_muTargetPolY;
static G4bool store_muTargetPolZ;
static G4bool store_muM0Time;
static G4bool store_muM0PolX;
static G4bool store_muM0PolY;
static G4bool store_muM0PolZ;
static G4bool store_muM1Time;
static G4bool store_muM1PolX;
static G4bool store_muM1PolY;
static G4bool store_muM1PolZ;
static G4bool store_muM2Time;
static G4bool store_muM2PolX;
static G4bool store_muM2PolY;
static G4bool store_muM2PolZ;
static G4bool store_posIniMomX;
static G4bool store_posIniMomY;
static G4bool store_posIniMomZ;
static G4bool store_det_ID;
static G4bool store_det_edep;
static G4bool store_det_edep_el;
static G4bool store_det_edep_pos;
static G4bool store_det_edep_gam;
static G4bool store_det_edep_mup;
static G4bool store_det_nsteps;
static G4bool store_det_length;
static G4bool store_det_start;
static G4bool store_det_end;
static G4bool store_det_x;
static G4bool store_det_y;
static G4bool store_det_z;
static G4bool store_det_kine;
static G4bool store_det_VrtxKine;
static G4bool store_det_VrtxX;
static G4bool store_det_VrtxY;
static G4bool store_det_VrtxZ;
static G4bool store_det_VrtxVolID;
static G4bool store_det_VrtxProcID;
static G4bool store_det_VrtxTrackID;
static G4bool store_det_VrtxParticleID;
static G4bool store_det_VvvKine;
static G4bool store_det_VvvX;
static G4bool store_det_VvvY;
static G4bool store_det_VvvZ;
static G4bool store_det_VvvVolID;
static G4bool store_det_VvvProcID;
static G4bool store_det_VvvTrackID;
static G4bool store_det_VvvParticleID;
static G4bool store_fieldNomVal;
static G4bool store_fieldIntegralBx;
static G4bool store_fieldIntegralBy;
static G4bool store_fieldIntegralBz;
static G4bool store_fieldIntegralBz1;
static G4bool store_fieldIntegralBz2;
static G4bool store_fieldIntegralBz3;
static G4int oldEventNumberInG4EqEMFieldWithSpinFunction;
private:
TFile* rootFile;
TTree* rootTree;
static musrRootOutput* pointerToRoot;
static const Int_t maxNGeantParameters=30;
Double_t GeantParametersD[maxNGeantParameters]; // parameters transfered from GEANT to Root
// 0 ... fieldOption: 0 ... no field, 1 ... uniform, 2 ... gaussian, 3 ... from table
// 1 ... fieldValue: intensity of the magnetic field
// 2 ... minimum of the generated decay time of the muon (in microsecond)
// 3 ... maximum of the generated decay time of the muon (in microsecond)
// 4 ... muon mean life time (in microsecond)
// 5 ... nr. of the last generated event
// 6 ... run number
// 7 ... numberOfGeneratedEvents (i.e. number of the generated events;
// in case of Turtle nr. of events tried);
// Variables common to the whole event:
Int_t runID_t;
Int_t eventID_t;
Double_t weight_t;
Double_t B_t[6];
Double_t muIniPosX_t, muIniPosY_t, muIniPosZ_t;
Double_t muIniMomX_t, muIniMomY_t, muIniMomZ_t;
Double_t muIniPolX_t, muIniPolY_t, muIniPolZ_t;
Int_t muDecayDetID_t;
Double_t muDecayPolX_t, muDecayPolY_t, muDecayPolZ_t;
Double_t muTargetTime_t, muTargetPolX_t, muTargetPolY_t, muTargetPolZ_t;
Double_t muM0Time_t, muM0PolX_t, muM0PolY_t, muM0PolZ_t;
Double_t muM1Time_t, muM1PolX_t, muM1PolY_t, muM1PolZ_t;
Double_t muM2Time_t, muM2PolX_t, muM2PolY_t, muM2PolZ_t;
Double_t muDecayPosX_t, muDecayPosY_t, muDecayPosZ_t;
Double_t muDecayTime_t;
Double_t posIniMomx_t, posIniMomy_t, posIniMomz_t;
public:
static const Int_t maxNFieldnNominalValues=30;
private:
Int_t nFieldNomVal;
Double_t fieldNomVal[maxNFieldnNominalValues];
Double_t BxIntegral_t, ByIntegral_t, BzIntegral_t;
Double_t BzIntegral1_t, BzIntegral2_t, BzIntegral3_t;
// Variables for a particle in a given detector within the event
public:
static const Int_t maxNSubTracks=30;
private:
// Variables for the activity inside a given detector
public:
static const Int_t det_nMax=100; // must be by 1 higher than the real number of detector "hits", because
// else the detector nr. 0 is counted (0 is used if no
// SensDetectorMapping correspond to a given logical volume).
private:
G4int det_n;
G4int det_ID[det_nMax];
G4double det_edep[det_nMax];
G4int det_nsteps[det_nMax];
G4double det_length[det_nMax];
G4double det_edep_el[det_nMax];
G4double det_edep_pos[det_nMax];
G4double det_edep_gam[det_nMax];
G4double det_edep_mup[det_nMax];
G4double det_time_start[det_nMax];
G4double det_time_end[det_nMax];
G4double det_x[det_nMax];
G4double det_y[det_nMax];
G4double det_z[det_nMax];
G4double det_kine[det_nMax];
G4double det_VrtxKine[det_nMax];
G4double det_VrtxX[det_nMax];
G4double det_VrtxY[det_nMax];
G4double det_VrtxZ[det_nMax];
G4int det_VrtxVolID[det_nMax];
G4int det_VrtxProcID[det_nMax];
G4int det_VrtxTrackID[det_nMax];
G4int det_VrtxParticleID[det_nMax];
G4double det_VvvKine[det_nMax];
G4double det_VvvX[det_nMax];
G4double det_VvvY[det_nMax];
G4double det_VvvZ[det_nMax];
G4int det_VvvVolID[det_nMax];
G4int det_VvvProcID[det_nMax];
G4int det_VvvTrackID[det_nMax];
G4int det_VvvParticleID[det_nMax];
public:
static const Int_t save_nMax=2000;
private:
G4int save_n;
G4int save_detID[save_nMax];
G4int save_particleID[save_nMax];
G4double save_ke[save_nMax];
G4double save_x[save_nMax];
G4double save_y[save_nMax];
G4double save_z[save_nMax];
G4double save_px[save_nMax];
G4double save_py[save_nMax];
G4double save_pz[save_nMax];
G4bool boolIsAnySpecialSaveVolumeDefined;
std::map<std::string,int> SensDetectorMapping;
std::map<std::string,int> ProcessIDMapping;
};
#endif

36
include/musrRunAction.hh Normal file
View File

@ -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

139
include/musrScintHit.hh Normal file
View File

@ -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<hit2.globalTime);}
inline void* operator new(size_t);
inline void operator delete(void*);
void Draw();
void Print();
public:
void SetParticleName (G4String name) {particleName = name; }
void SetParticleID (G4int id) {particleID = id; }
void SetTrackID (G4int track) { trackID = track; }
void SetEdep (G4double de) { edep = de; }
void SetPrePos (G4ThreeVector xyz){ pre_pos = xyz; }
void SetPostPos (G4ThreeVector xyz){ post_pos = xyz; }
void SetPol (G4ThreeVector ijk){pol = ijk;}
void SetLogVolName (G4String logivol) {logicalVolume = logivol;}
void SetGlobTime (G4double gt) { globalTime = gt;}
void SetFirstStepInVolumeFlag (G4bool flag) { firstStepInVolume=flag;}
void SetLastStepInVolumeFlag (G4bool flag) { lastStepInVolume=flag;}
void SetKineticEnergy (G4double en) { kineticEnergy = en;}
void SetStepLength (G4double length) { stepLength = length;}
void SetRunID(G4int i) {runID=i;}
void SetEventID(G4int i) {eventID=i;}
void SetVertexPosition(G4ThreeVector xyz) {vertexPosition = xyz; }
void SetVertexKineticEnergy(G4double Ek) {vertexKineticEnergy = Ek; }
void SetLogicalVolumeAtVertex(G4String logivol) {logicalVolumeAtVertex = logivol; }
void SetCreatorProcessName(G4String name) {creatorProcess = name; }
// void SetVerboseLevel (G4int n) { G4int musrScintHit::verboseLevel=n;};
G4String GetParticleName() {return particleName; }
G4int GetParticleID() {return particleID; }
G4int GetTrackID() { return trackID; }
G4double GetEdep() { return edep; }
G4ThreeVector GetPrePos(){ return pre_pos; }
G4ThreeVector GetPostPos(){ return post_pos; }
G4ThreeVector GetPol(){ return pol; }
G4String GetLogVolName() { return logicalVolume; }
G4double GetGlobalTime() { return globalTime; }
G4bool GetFirstStepInVolumeFlag() {return firstStepInVolume;}
G4bool GetLastStepInVolumeFlag() {return lastStepInVolume;}
G4double GetKineticEnergy() { return kineticEnergy; }
G4double GetStepLength() {return stepLength; }
G4double* GetBField () {return BF;}
G4int GetRunID() {return runID;}
G4int GetEventID() {return eventID;}
G4ThreeVector GetVertexPosition() { return vertexPosition; }
G4double GetVertexKineticEnergy() { return vertexKineticEnergy; }
G4String GetLogicalVolumeAtVertex() { return logicalVolumeAtVertex; }
G4String GetCreatorProcessName() { return creatorProcess; }
G4double point[4];
G4double B[6];
const G4Field *mfield;
private:
G4String particleName;
G4int particleID;
G4int trackID;
G4double edep;
G4ThreeVector pre_pos;
G4ThreeVector post_pos;
G4ThreeVector pol;
G4String logicalVolume;
G4double globalTime;
G4bool firstStepInVolume;
G4bool lastStepInVolume;
G4double kineticEnergy;
G4double stepLength;
G4int eventID;
G4int runID;
G4double BF[6];
G4ThreeVector vertexPosition; // Position of the vertex at which the actual track was created
G4double vertexKineticEnergy; // Kinetic energy of the track when it was created
G4String logicalVolumeAtVertex;
G4String creatorProcess;
static G4int ScintMultihit;
static G4int runIDoldScint;
static G4int eventIDoldScint;
static G4int NIS;
static G4int ScintChamberNbold;
static G4int verboseLevel;
};
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
typedef G4THitsCollection<musrScintHit> musrScintHitsCollection;
extern G4Allocator<musrScintHit> 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

38
include/musrScintSD.hh Normal file
View File

@ -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

View File

@ -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 <fstream>
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<G4String,G4int> saveVolumeMapping;
G4String lastActualVolume;
G4bool boolMuonEventReweighting;
G4bool boolCalculateFieldIntegral;
std::map<G4String,G4int> volumeMuonWeightMapping;
G4int indexOfOldTrack;
std::map<G4int,G4int> 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

View File

@ -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

View File

@ -0,0 +1,68 @@
#ifndef musrTabulatedElementField_h
#define musrTabulatedElementField_h 1
#include "globals.hh"
#include "F04ElementField.hh"
#include "F04GlobalField.hh"
#include "G4ios.hh"
#include <fstream>
#include <vector>
#include <cmath>
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

View File

@ -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

44
include/yields.hh Normal file
View File

@ -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

151
musrSim.cc Normal file
View File

@ -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 <TPluginManager::FindHandler>: Cannot find plugin handler for TVirtualStreamerInfo!
// Does $ROOTSYS/etc/plugins/TVirtualStreamerInfo exist?"
#include "TROOT.h"
#include "TPluginManager.h"
#include "Randomize.hh"
#include <X11/Xlib.h>
#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 <TPluginManager::FindHandler>: 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;
}

812
run/1050.mac Normal file
View File

@ -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 <volume parameters> Material X Y Z MotherVolume RotationMatrix Sensitivity RootID [nofield]
# Type - can be tubs (cylindrical), box, sphere etc.
# Name - Just the name of the volume
# <volume parameters> - 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

View File

@ -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

200
src/F04ElementField.cc Normal file
View File

@ -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: "<<G4endl;
F04GlobalField::getObject()->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="<<center.x()/mm<<", "<<center.y()/mm<<", "<<center.z()/mm<<" mm"<<G4endl;
aNavigator->LocateGlobalPointAndSetup(center,0,false);
G4TouchableHistoryHandle fTouchable = aNavigator->
CreateTouchableHistoryHandle();
G4int depth = fTouchable->GetHistoryDepth();
for (G4int i = 0; i<depth; ++i) {
if(fTouchable->GetVolume()->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: "<<fTouchable->GetVolume()->GetName()<<G4endl;
// Set global2local transform. The centre of the transformation is set to the centre of the volume, not
// to the point "center", as one could naively expect. This is corrected a few lines later.
global2local = fTouchable->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==> "<<elementFieldName<<" in vol.=\""<<volumeName<<"\", center(local coord. system): "
<<local_center.x()/mm<<", "<<local_center.y()/mm<<", "<<local_center.z()/mm<<" mm."<<G4endl;
// Now move the centre of the transformation such that it coincides with the point "center":
global2local*=G4AffineTransform(-local_center);
// After moving the centre of the transformation, the point "local_center" should be set to 0., 0., 0. in
// the following print-out message:
// local_center = global2local.TransformPoint(center);
// G4cout<<"\t==> "<<elementFieldName<<" (volume=\""<<volumeName<<"\", center of the field in local coordinate syst 2: "
// <<local_center.x()/mm<<", "<<local_center.y()/mm<<", "<<local_center.z()/mm<<" mm.)"<<G4endl;
// set global bounding box
G4double local[4], global[4];
G4ThreeVector globalPosition;
local[3] = 0.0;
for (int i=0; i<2; ++i) {
local[0] = (i==0 ? -1.0 : 1.0) * getWidth()/2.;
for (int j=0; j<2; ++j) {
local[1] = (j==0 ? -1.0 : 1.0) * getHeight()/2.;
for (int k=0; k<2; ++k) {
local[2] = (k==0 ? -1.0 : 1.0) * getLength()/2.;
G4ThreeVector localPosition(local[0],local[1],local[2]);
globalPosition =
global2local.Inverse().TransformPoint(localPosition);
global[0] = globalPosition.x();
global[1] = globalPosition.y();
global[2] = globalPosition.z();
setGlobalPoint(global);
}
}
}
}
G4VisAttributes* F04ElementField::getVisAttribute(G4String color)
{
G4VisAttributes* p = NULL;
if(color.size() > 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="<<musrParameters::nrOfEventsToBeGenerated<<G4endl;
// G4cout<<"fieldStep="<<fieldStep<<" eventNrStep="<<eventNrStep<<G4endl;
for (G4int i=1; i<=nrOfSteps; i++) {
G4int eventNumber = int(i*eventNrStep);
G4double field = initialField + i*fieldStep;
changeFieldInStepsMap[eventNumber]=field;
}
G4cout << "Setting field in steps for field "<<elementFieldName<<G4endl;
std::map<G4int,G4double>::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<G4int,G4double>::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 "<<G4endl;
}
}

147
src/F04FieldMessenger.cc Normal file
View File

@ -0,0 +1,147 @@
//
// ********************************************************************
// * 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 "F04FieldMessenger.hh"
#include "F04GlobalField.hh"
#include "G4UIdirectory.hh"
#include "G4UIcmdWithAString.hh"
#include "G4UIcmdWithAnInteger.hh"
#include "G4UIcmdWithADoubleAndUnit.hh"
#include "G4UIcmdWithoutParameter.hh"
//////////////////////////////////////////////////////////////////////////////
F04FieldMessenger::F04FieldMessenger(F04GlobalField* pEMfield)
: fGlobalField(pEMfield)
{
detDir = new G4UIdirectory("/field/");
detDir->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));
}
}

330
src/F04GlobalField.cc Normal file
View File

@ -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 <time.h>
#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 ("<<point[0]<<","<<point[1]<<","<<point[2]<<")"<<G4endl;
//cks Check whether the requested point is the same as in the previous call
// if (myOldFieldPoints.ThisPointWasCalculatedRecently(point,field)) {return;}
field[0] = field[1] = field[2] = field[3] = field[4] = field[5] = 0.0;
// protect against Geant4 bug that calls us with point[] NaN.
if(point[0] != point[0]) return;
// (can't use nfp or fp, as they may change)
if (first) ((F04GlobalField*)this)->setupArray(); // (cast away const)
for (int i=0; i<nfp; ++i) {
const F04ElementField* p = fp[i];
if (p->isInBoundingBox(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<nfp; ++i) {
fp[i] = (*fields)[i];
//
// Find the event numbers, for which the field changes, for each Element Field.
// Then mark these event numbers in the Global Field, such that it can be efficiently
// find out during the run-time, at which event number the field may change.
std::map<G4int,G4double> localChangeFieldInStepsMap = fp[i] ->GetEventNrDependentField();
std::map<G4int,G4double>::iterator it;
for ( it=localChangeFieldInStepsMap.begin() ; it != localChangeFieldInStepsMap.end(); it++ ) {
G4int eventNr = it->first;
G4cout<<"globalChangeFieldInStepsMap set for event number "<<eventNr<<G4endl;
globalChangeFieldInStepsMap[eventNr]=true;
}
}
musrRootOutput::GetRootInstance()->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:"<<G4endl;
G4int jjj=0;
FieldList::iterator i;
for (i=fields->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));
}
}

220
src/G4DecayWithSpin.cc Normal file
View File

@ -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="<<parent_polarization<<", B="<<B[0]/tesla<<","<<B[1]/tesla<<","<<B[2]/tesla
// <<", fRemainderLifeTime="<<fRemainderLifeTime<<G4endl;
}
}
}
// decay table
G4DecayTable *decaytable = aParticleDef->GetDecayTable();
if (decaytable) {
G4MuonDecayChannelWithSpin *decaychannel;
decaychannel = (G4MuonDecayChannelWithSpin*)decaytable->SelectADecayChannel();
if (decaychannel) decaychannel->SetPolarization(parent_polarization);
}
G4ParticleChangeForDecay* pParticleChangeForDecay;
pParticleChangeForDecay = (G4ParticleChangeForDecay*)G4Decay::DecayIt(aTrack,aStep);
pParticleChangeForDecay->ProposePolarization(parent_polarization);
// pParticleChangeForDecay->DumpInfo();
return pParticleChangeForDecay;
}
G4ThreeVector G4DecayWithSpin::Spin_Precession( const G4Step& aStep,
G4ThreeVector B, G4double deltatime )
{
G4double Bnorm = std::sqrt(sqr(B[0]) + sqr(B[1]) +sqr(B[2]) );
G4double q = aStep.GetTrack()->GetDefinition()->GetPDGCharge();
G4double a = 1.165922e-3;
G4double s_omega = 8.5062e+7*rad/(s*kilogauss);
G4double omega = -(q*s_omega)*(1.+a) * Bnorm;
G4double rotationangle = deltatime * omega;
G4Transform3D SpinRotation = G4Rotate3D(rotationangle,B.unit());
G4Vector3D Spin = aStep.GetTrack() -> GetPolarization();
//cks 2008.10.09. Check that the polarisatin is normalised do 1
G4double spinMagnitude = Spin.mag();
if ((spinMagnitude>1.1)||(spinMagnitude<0.9)) {
G4RunManager* fRunManager = G4RunManager::GetRunManager();
G4int eventNr=fRunManager->GetCurrentEvent()->GetEventID();
musrErrorMessage::GetInstance()->musrError(SERIOUS,
"G4DecayWithSpin.cc::Spin_Precession: spin magnitude is large than 1.1 or smaller than 0.9! Strange!!!",true);
G4cout<<"G4DecayWithSpin.cc::Spin_Precession: "
<<"Event nr.:"<<eventNr
<<", spin = ("<<Spin.x()<<","<<Spin.y()<<","<<Spin.z()<<")."<<G4endl;
G4cout.flush();
}
Spin = Spin.unit();
//csk
G4Vector3D newSpin = SpinRotation * Spin;
//cks 2008.10.09. Check that the polarisatin is normalised do 1
G4double newSpinMagnitude = newSpin.mag();
if ((newSpinMagnitude>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.:"<<eventNr
<<", NEW spin = ("<<newSpin.x()<<","<<newSpin.y()<<","<<newSpin.z()<<")."<<G4endl;
G4cout.flush();
}
newSpin = newSpin.unit();
//csk
#ifdef G4VERBOSE
if (GetVerboseLevel()>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;
}

177
src/G4EqEMFieldWithSpin.cc Normal file
View File

@ -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.:"<<eventNr<<", particle mass = "<<sqrt(fMassCof)/MeV<<" MeV"
// <<", spin = ("<<Spin.x()<<","<<Spin.y()<<","<<Spin.z()<<")."<<G4endl;
// G4cout.flush();
// musrRootOutput::GetRootInstance()->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.:"<<eventNr<<", particle mass = "<<sqrt(fMassCof)/MeV<<" MeV"
// <<", spin = ("<<Spin.x()<<","<<Spin.y()<<","<<Spin.z()<<")."<<G4endl;
// G4cout.flush();
// musrRootOutput::GetRootInstance()->SetEventWeight(0);
// fRunManager->AbortEvent();
// }
// }
//
// csk
dydx[ 9] = dSpin.x();
dydx[10] = dSpin.y();
dydx[11] = dSpin.z();
return ;
}

202
src/MuDecayChannel.cc Normal file
View File

@ -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 " <<G4endl;
products->DumpInfo();
}
#endif
return products;
}

View File

@ -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"<<G4endl;
FG_max = FG;
}
rndm = G4UniformRand();
}while(FG<rndm*FG_max);
G4double energy = x * W_mue;
rndm = G4UniformRand();
G4double phi = twopi * rndm;
if(energy < EMASS) energy = EMASS;
// calculate daughter momentum
G4double daughtermomentum[3];
daughtermomentum[0] = std::sqrt(energy*energy - EMASS*EMASS);
G4double stheta = std::sqrt(1.-ctheta*ctheta);
G4double cphi = std::cos(phi);
G4double sphi = std::sin(phi);
//Coordinates of the decay positron with respect to the muon spin
G4double px = stheta*cphi;
G4double py = stheta*sphi;
G4double pz = ctheta;
G4ThreeVector direction0(px,py,pz);
direction0.rotateUz(parent_polarization);
G4DynamicParticle * daughterparticle0
= new G4DynamicParticle( daughters[0], daughtermomentum[0]*direction0);
products->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 " <<G4endl;
products->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;
}

1032
src/meyer.cc Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
#include "musrDetectorMessenger.hh"
#include "musrDetectorConstruction.hh"
#include "G4UIdirectory.hh"
#include "G4UIcmdWithAString.hh"
#include "G4UIcmdWithADoubleAndUnit.hh"
#include "G4UIcmdWithAnInteger.hh"
#include "G4UIcmdWithoutParameter.hh"
#include "G4UIcmdWith3Vector.hh"
#include "G4UIcmdWith3VectorAndUnit.hh"
#include "G4RunManager.hh" //cks included in order to be able to change run ID
#include "Randomize.hh" //cks included in order to initialise the random nr. generator by time
#include <time.h> //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 <vector>
#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<int> * 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()<<G4endl;
}
else if (RandomOption == 4) {
G4cout << "*********************************************" << G4endl;
G4cout << "*** Random Seed set from kamil.rndm file ***" << G4endl;
G4cout << "*********************************************" << G4endl;
musrPrimaryGeneratorAction::setRandomNrSeedFromFile_RNDM=1;
}
}
if ( command == HowOftenToPrintEventCmd )
{
G4int n = HowOftenToPrintEventCmd->GetNewIntValue(newValue);
musrEventAction::nHowOftenToPrintEvent=n;
}
if ( command == RndmEventToSaveSeedsCmd )
{
G4int n = RndmEventToSaveSeedsCmd->GetNewIntValue(newValue);
musrPrimaryGeneratorAction::nRndmEventToSaveSeeds=n;
}
}

62
src/musrErrorMessage.cc Normal file
View File

@ -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<G4String,ErrorStruct>::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<<"!!!"<<severityWord[severity]<<"!!! "<<message<<" (First time occurrence)"<<G4endl;
nErrors++;
}
else { // The error message is called for more than the first time
(*it).second.nTimes++;
}
// Print out the error message if required
if ((!silent)||(severity==FATAL)) {
if ((*it).second.nTimes>1) {
G4cout<<"!!!"<<severityWord[severity]<<"!!! "<<message
<<" ("<<(*it).second.nTimes<<" occurences)"<<G4endl;
}
}
if (severity==FATAL) {
G4cout<<"S T O P F O R C E D!"<<G4endl;
exit(1);
}
}
void musrErrorMessage::PrintErrorSummary() {
std::map<G4String,ErrorStruct>::iterator it;
G4cout<<"------ ERROR SUMMARY: ----------------------------------------------------------------"<<G4endl;
for (G4int i=0; i<4; i++) {
for ( it=ErrorMapping.begin() ; it != ErrorMapping.end(); it++ ) {
if ((*it).second.mesSeverity==i) {
G4cout<<severityWord[(*it).second.mesSeverity]<<" ("<<(*it).second.nTimes<<" times):"
<< (*it).first <<G4endl;
}
}
}
G4cout<<"-----------------------------------------------------------------------------------------"<<G4endl;
}

92
src/musrEventAction.cc Normal file
View File

@ -0,0 +1,92 @@
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
#include "musrEventAction.hh"
#include "G4Event.hh"
#include "G4EventManager.hh"
#include "G4TrajectoryContainer.hh"
#include "G4Trajectory.hh"
#include "G4VVisManager.hh"
#include "G4ios.hh"
#include "G4TransportationManager.hh"
#include "G4FieldManager.hh"
#include "musrRootOutput.hh"
#include "musrErrorMessage.hh"
#include "musrSteppingAction.hh"
#include "F04GlobalField.hh"
#include "G4RunManager.hh" // needed just in order to save random number generator seed
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4int musrEventAction::nHowOftenToPrintEvent=10000;
G4double musrEventAction::maximumRunTimeAllowed=85000;
musrEventAction::musrEventAction() {
pointer=this;
}
musrEventAction* musrEventAction::pointer=0;
musrEventAction* musrEventAction::GetInstance() {
return pointer;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
musrEventAction::~musrEventAction()
{
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void musrEventAction::BeginOfEventAction(const G4Event* evt) {
// G4cout<<"musrEventAction::BeginOfEventAction:"<<G4endl;
long thisEventNr = (long) (evt->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 "<<curr-timeOfRunStart<<" seconds. Present time: "<< ctime(&curr);
G4cout.flush();
// G4cout << " seed set to "<< CLHEP::HepRandom::getTheSeed();//<< G4endl;
}
// extract the trajectories and draw them
if (G4VVisManager::GetConcreteInstance()) {
for (G4int i=0; i<n_trajectories; i++)
{ G4Trajectory* trj = (G4Trajectory*)
((*(evt->GetTrajectoryContainer()))[i]);
trj->DrawTrajectory(1000);
}
}
}

111
src/musrMuFormation.cc Normal file
View File

@ -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(rnd<yvector[0])
{
particle = particleTable->FindParticle(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());
}
}

86
src/musrMuScatter.cc Normal file
View File

@ -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());
}

112
src/musrMuonium.cc Normal file
View File

@ -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<musrMuonium*>(anInstance);
return theInstance;
}
musrMuonium* musrMuonium::MuoniumDefinition()
{
return Definition();
}
musrMuonium* musrMuonium::Muonium()
{
return Definition();
}

91
src/musrParameters.cc Normal file
View File

@ -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=\""<<steeringFileName
<<"\" not opened for some reason."<<G4endl;
G4cout << "S T O P F O R C E D" << G4endl;
exit(1);
}
G4cout<<"musrParameters::musrParameters: steeringFileName=\""<<steeringFileName<<"\" opened."<<G4endl;
char line[501];
while (!feof(fSteeringFile)) {
fgets(line,500,fSteeringFile);
if ((line[0]!='#')&&(line[0]!='\n')&&(line[0]!='\r')) {
char tmpString0[100]="Unset";
sscanf(&line[0],"%s",tmpString0);
// First find out how many events will be generated (needs to be known at an early stage, if the
// field is to be set in steps):
if (strcmp(tmpString0,"/run/beamOn")==0) {
int nev;
sscanf(&line[0],"%*s %d", &nev);
musrParameters::nrOfEventsToBeGenerated = nev;
}
if (strncmp(tmpString0,"/gps/",5)==0) {
musrParameters::boolG4GeneralParticleSource = true;
G4cout<<"\n========================================================================"<<G4endl;
G4cout<<"musrParameters.cc: GPS (General Particle Source) requested in the macro."<<G4endl;
G4cout<<" GPS will be used instead of the primary generator action."<<G4endl;
}
// Now find some private parameters that need to be initialised at early stage
if ( (strcmp(tmpString0,"/musr/ignore")!=0)&&(strcmp(tmpString0,"/musr/command")!=0) ) continue;
char tmpString1[100]="Unset", tmpString2[100]="Unset", tmpString3[100]="Unset";
sscanf(&line[0],"%*s %s %s %s",tmpString1,tmpString2,tmpString3);
// if (strcmp(tmpString1,"G4GeneralParticleSource")==0){
// if (strcmp(tmpString2,"true")==0){ musrParameters::boolG4GeneralParticleSource = true; }
// }
if (strcmp(tmpString1,"G4OpticalPhotons")==0){
if (strcmp(tmpString2,"true")==0){ musrParameters::boolG4OpticalPhotons = true; }
}
if (strcmp(tmpString1,"region")==0) {
boolG4RegionRequested = true;
}
if ( (strcmp(tmpString1,"construct")==0) && boolG4RegionRequested) {
G4cout<<"musrParameters.cc: User requests to construct a detector volume "<<tmpString3<<G4endl;
G4cout<<" after a previous G4Region definition."<<G4endl;
G4cout<<" Perhaps not a crutial problem, but the execution will be stopped"<<G4endl;
G4cout<<" anyway just to be on the safe side. Please correct "<<steeringFileName<<" file"<<G4endl;
G4cout<<" such that G4Region is called only after all detector volumes have been created."<<G4endl;
G4cout<<" S T O P F O R C E D!"<<G4endl;
exit(1);
}
}
}
fclose(fSteeringFile);
}
musrParameters::~musrParameters() {}
musrParameters* musrParameters::pointerToParameters=NULL;
musrParameters* musrParameters::GetInstance() {
return pointerToParameters;
}
G4String musrParameters::mySteeringFileName="Unset";
G4bool musrParameters::storeOnlyEventsWithHits=true;
G4int musrParameters::storeOnlyEventsWithHitInDetID=0;
G4double musrParameters::signalSeparationTime=100*nanosecond;
G4bool musrParameters::storeOnlyTheFirstTimeHit=false;
G4bool musrParameters::field_DecayWithSpin=false;
G4bool musrParameters::killAllPositrons=false;
G4bool musrParameters::killAllGammas=false;
G4bool musrParameters::killAllNeutrinos=true;
G4bool musrParameters::boolG4GeneralParticleSource=false;
G4bool musrParameters::boolG4OpticalPhotons=false;
//cks G4bool musrParameters::includeMuoniumProcesses =true; // TS
//G4bool musrParameters::boolG4GeneralParticleSource=true;
G4int musrParameters::nrOfEventsToBeGenerated=0;

444
src/musrPhysicsList.cc Normal file
View File

@ -0,0 +1,444 @@
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
#include "globals.hh"
#include "G4ios.hh"
#include "musrPhysicsList.hh"
#include "G4VPhysicsConstructor.hh"
#include "G4ProcessManager.hh"
#include "G4ParticleTypes.hh"
#include "G4MuonDecayChannel.hh"
#include "G4DecayTable.hh"
//cks Added to have Geant default muon decay with spin
#include "G4MuonDecayChannelWithSpin.hh"
#include "G4MuonRadiativeDecayChannelWithSpin.hh"
#include "G4RadioactiveDecay.hh"
#include "G4IonConstructor.hh"
//TS Classes which account for Muonium as "particle" and its spin
#include "musrMuonium.hh"
#include "MuDecayChannel.hh"
#include "MuDecayChannelWithSpin.hh"
//
#include "musrParameters.hh"
#include "musrErrorMessage.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
musrPhysicsList::musrPhysicsList(): G4VUserPhysicsList()
{
defaultCutValue = 0.1*mm;
SetVerboseLevel(0);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
musrPhysicsList::~musrPhysicsList()
{}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void musrPhysicsList::ConstructParticle()
{
ConstructBosons();
ConstructLeptons();
ConstructMesons();
ConstructBaryons();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void musrPhysicsList::ConstructBosons()
{
// pseudo-particles
G4Geantino::GeantinoDefinition();
G4ChargedGeantino::ChargedGeantinoDefinition();
// gamma
G4Gamma::GammaDefinition();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void musrPhysicsList::ConstructLeptons()
{
// leptons
// e+/-
G4Electron::ElectronDefinition();
G4Positron::PositronDefinition();
// mu+/-
G4MuonPlus::MuonPlusDefinition();
G4MuonMinus::MuonMinusDefinition();
//cks
// G4DecayTable* MuonPlusDecayTable = new G4DecayTable();
// MuonPlusDecayTable -> 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:"<<G4endl;}
char line[501];
while (!feof(fSteeringFile)) {
fgets(line,500,fSteeringFile);
if ((line[0]!='#')&&(line[0]!='\n')&&(line[0]!='\r')) {
char tmpString0[100]="Unset", tmpString1[100]="Unset",tmpString2[100]="Unset";
sscanf(&line[0],"%s %s %s",tmpString0,tmpString1,tmpString2);
if ( (strcmp(tmpString0,"/musr/ignore")!=0)&&(strcmp(tmpString0,"/musr/command")!=0) ) continue;
if (strcmp(tmpString1,"process")!=0) continue;
if ((strcmp(tmpString2,"addProcess")==0)||(strcmp(tmpString2,"addDiscreteProcess")==0)) {
char charParticleName[100], charProcessName[100];
sscanf(&line[0],"%*s %*s %s %s %s",tmpString2,charParticleName,charProcessName);
G4cout<<"musrPhysicsList: Defining process "<<charProcessName<<" for "<<charParticleName<<G4endl;
G4String stringProcessName = charProcessName;
G4String stringParticleName = charParticleName;
G4ParticleDefinition* particleDefinition = G4ParticleTable::GetParticleTable() -> FindParticle(stringParticleName);
// G4cout<<"particleDefinition of "<<stringParticleName<<" = "<<particleDefinition<<G4endl;
if (particleDefinition==NULL) {
sprintf(eMessage,"musrPhysicsList: Partile \"%s\" not found in G4ParticleTable when trying to assign process \"%s\".",
charParticleName,charProcessName);
musrErrorMessage::GetInstance()->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 "<<charRegion1<<G4endl;
multScat->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 "<<charRegion2<<G4endl;
multScat->AddEmModel(0,coulScatModel,regionForCoulomb);
}
if (strcmp(charRegion3,"")!=0) {
G4Region* regionForCoulomb = FindG4Region(charRegion3,line);
G4cout<<" Adding Coulomb scattering model to multiple scattering model for region "<<charRegion3<<G4endl;
multScat->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."<<G4endl;
G4cout<<"Please extend the number of supported regions in musrPhysicsList.cc to higher number."<<G4endl;
G4cout<<"The extention of the code to larger number of regions is not very difficult."<<G4endl;
G4cout<<" S T O P F O R C E D"<<G4endl;
exit(1);
}
pManager->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"<<G4endl;
// csk 2008.08.22.
//del G4String myTypeOfProcesses = musrParameters::GetInstance()->GetMyTypeOfProcesses();
//del G4cout<<"musrPhysicsList::ConstructEM(): myTypeOfProcesses="<<myTypeOfProcesses<<G4endl;
theParticleIterator->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 :"<<G4endl;
G4cout<<" "<<myString<<G4endl;
G4cout<<"S T O P F O R C E D!"<<G4endl;
exit(1);
}
G4Region* musrPhysicsList::FindG4Region(G4String regionName, char* lineOfSteeringFile) {
G4Region* myRegion = G4RegionStore::GetInstance()->GetRegion(regionName,false);
if( myRegion != NULL ) { // G4Region found
return myRegion;
}
else { // G4Region not found
G4cout<<"musrPhysicsList: G4Region "<<regionName<<" not found."<<G4endl;
G4cout<<" The critical command line of the steering file is:"<<G4endl;
G4cout<<" "<<lineOfSteeringFile<<G4endl;
G4cout<<" S T O P F O R C E D"<<G4endl;
exit(1);
}
}

View File

@ -0,0 +1,427 @@
#include "musrPrimaryGeneratorAction.hh"
#include "musrDetectorConstruction.hh"
#include "musrPrimaryGeneratorMessenger.hh"
#include "musrParameters.hh"
#include "G4Event.hh"
#include "G4GeneralParticleSource.hh"
#include "G4ParticleGun.hh"
#include "G4ParticleTable.hh"
#include "Randomize.hh"
#include "G4ios.hh"
#include "G4UnitsTable.hh"
#include "globals.hh"
#include "G4Gamma.hh"
#include "G4ThreeVector.hh"
#include "G4RunManager.hh"
#include "time.h"
#include <iomanip>
#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<int> * musrPrimaryGeneratorAction::pointerToSeedVector=NULL;
std::vector<int> * 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<int>;
// 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"<<G4endl;
particleSource = new G4GeneralParticleSource ();
}
else {
G4cout<<"musrPrimaryGeneratorAction: G4ParticleGun is going to be initialised"<<G4endl;
particleGun = new G4ParticleGun(n_particle);
particleGun->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 = "<<numberOfGeneratedEvents<<G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
void musrPrimaryGeneratorAction::GeneratePrimaries(G4Event* anEvent)
{
// This function is called at the begining of event.
// Clear Root variables
musrRootOutput* myRootOutput = musrRootOutput::GetRootInstance();
myRootOutput->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 = "<<numberOfGeneratedEvents<<")"<<G4endl;
fgets(line,500,fTurtleFile);
}
numberOfGeneratedEvents++;
sscanf(&line[0],"%g %g %g %g %g %g %g %d %d",&xTmp,&xAngleTmp,&yTmp,&yAngleTmp,&pTmp,&dummy1,&dummy2,&Ztmp,&Atmp);
if (boolPrintInfoAboutGeneratedParticles) {
G4cout<<"musrPrimaryGeneratorAction::GeneratePrimaries: Turtle input for this event: "
<<xTmp<<", "<<xAngleTmp<<" "<<yTmp<<" "<<yAngleTmp<<" "<< pTmp<<G4endl;
}
//cks Implement also alpha and proton particles for the simulation of Juan Pablo Urrego
if ((Ztmp==1)&&(Atmp==1)) {particleGun->SetParticleDefinition(protonParticle);}// G4cout<<"proton"<<G4endl;}
else if ((Ztmp==2)&&(Atmp==4)) {particleGun->SetParticleDefinition(alphaParticle);}// G4cout<<"alpha particle"<<G4endl;}
else if ((Ztmp==-1)&&(Atmp==-1)) {;}
else {
G4cout<<"musrPrimaryGeneratorAction: Unknown particle requested in the TURTLE input file: Z="
<<Ztmp<<", A="<<Atmp<<G4endl<<"S T O P F O R C E D" << G4endl;
G4cout<<xTmp<<", "<<xAngleTmp<<", "<<yTmp<<", "<<yAngleTmp<<", "<<pTmp<<", "<<dummy1<<", "<<dummy2<<", "<<Ztmp<<", "<<Atmp<<G4endl;
exit(1);
}
//csk
xangle = xAngleTmp*mrad;
yangle = yAngleTmp*mrad;
x = xTmp*cm + (z0-z0_InitialTurtle)*tan(xangle) ; // usually z0 is negative
y = yTmp*cm + (z0-z0_InitialTurtle)*tan(yangle) ; // z0_InitialTurtle is the z0 at whith the turtle file was generated.
p = pTmp*GeV;
// add some offset, if requested:
x = x + x0;
y = y + y0;
// add some beam tilt, if requested:
xangle = xangle + xangle0;
yangle = yangle + yangle0;
// add some beam pitch, if requested:
if (pitch!=0) {
xangle += - pitch * (x-x0);
yangle += - pitch * (y-y0);
}
// add/remove some momentum smearing, if requested
if (turtleMomentumBite) {
p = turtleMomentumP0 - (turtleMomentumP0-p)*turtleSmearingFactor;
}
checkNrOfCounts++;
if (checkNrOfCounts>1000) {
G4cout<<"musrPrimaryGeneratorAction::GeneratePrimaries: Too strict requirements on the r position!"<<G4endl;
}
} while( (x*x+y*y)>(rMaxAllowed*rMaxAllowed) );
z=z0;
// G4cout<<"x,y,z=("<<x/mm<<","<<y/mm<<","<<z/mm<<"), angles="<<xangle/mrad<<","<<yangle/mrad<<" p="<<p/MeV<<G4endl;
}
else { // Generate the starting position of the muon by random
// rMaxAllowed ... maximal radius, within which the muon can be generated
// x0, y0, z0 ... central point around which the muons are generated
// xSigma, ySigma, zSigma ... sigma of the (gaussian) distributions of the beam
// x, y, z ... actual initial position of the generated muon
G4int checkNrOfCounts=0;
numberOfGeneratedEvents++;
do {
if (xSigma>0) {x = G4RandGauss::shoot(x0,xSigma);} // Gaussian distribution
else if (xSigma<0) {x = x0 + xSigma*(G4UniformRand()*2.-1.);} // Uniform step distribution
else { x = x0;} // Point-like
if (ySigma>0) {y = G4RandGauss::shoot(y0,ySigma);}
else if (ySigma<0) {y = y0 + ySigma*(G4UniformRand()*2.-1.);}
else {y = y0;}
if (zSigma>0) {z = G4RandGauss::shoot(z0,zSigma);}
else if (zSigma<0) {z = z0 + zSigma*(G4UniformRand()*2.-1.);}
else {z = z0;}
checkNrOfCounts++;
if (checkNrOfCounts>1000) {
G4cout<<"musrPrimaryGeneratorAction::GeneratePrimaries: Too strict requirements on the r or z position!"<<G4endl;
}
} while( ((x*x+y*y)>(rMaxAllowed*rMaxAllowed))||(z>zMaxAllowed)||(z<zMinAllowed) );
// The generated muon has to stay
// within some well defined region,
// e.g. within the beampipe
// Now generate the momentum
checkNrOfCounts=0;
do {
if (pSigma>0) {p = G4RandGauss::shoot(p0,pSigma);}
else {p=p0;}
checkNrOfCounts++;
if (checkNrOfCounts>1000) {
G4cout<<"musrPrimaryGeneratorAction::GeneratePrimaries: Too strict requirements on the momentum!"<<G4endl;
}
} while ( (p>pMaxAllowed)||(p<pMinAllowed) );
// Add some initial angle (px and py component of the momentum)
if (xangleSigma>0) { 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"<<G4endl;
}
else {
xpolaris = -xPolarisIni; ypolaris = -yPolarisIni; zpolaris = -zPolarisIni;
// G4cout<<"spin down"<<G4endl;
}
}
particleGun->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:"<<G4endl;
// G4cout<<" x0,y0,z0="<<x0/mm<<","<<y0/mm<<","<<z0/mm<<" Sigma="<<xSigma/mm<<","<<ySigma/mm<<","<<zSigma/mm<<G4endl;
// G4cout<<" rMaxAllowed="<<rMaxAllowed/mm<<" zMaxAllowed="<<zMaxAllowed/mm<<" zMinAllowed="<<zMinAllowed/mm<<G4endl;
// G4cout<<" p0="<<p0/MeV<<" pSigma="<<pSigma/MeV
// <<" pMinAllowed="<<pMinAllowed/MeV<<" pMaxAllowed=<<"<<pMaxAllowed/MeV<<G4endl;
// G4cout<<" angle0="<<xangle0/deg<<","<<yangle0/deg<<",nic"
// <<" Sigma="<<xangleSigma/deg<<","<<yangleSigma/deg<<",nic"<<G4endl;
// G4cout<<" pitch="<<pitch/deg<<G4endl;
//
// G4cout<<"musrPrimaryGeneratorAction: Generated muon:"<<G4endl;
// G4cout<<" x,y,z="<<x/mm<<","<<y/mm<<","<<z/mm<<" angle="<<xangle/deg<<","<< yangle/deg<<",nic"<<G4endl;
// G4cout<<" p="<<px/MeV<<","<<py/MeV<<","<<pz/MeV<<" E="<< (particleGun->GetParticleEnergy())/MeV<<G4endl;
// G4cout<<" polarisation="<<xpolaris<<","<<ypolaris<<","<<zpolaris<<G4endl;
// if requested by "/gun/decaytimelimits", set the decay time of the muon such that it is within
// the required time window. Otherwise the decay time is set internally by Geant.
if (muonDecayTimeMax>0.) {
// G4cout<<"muonDecayTimeMin="<<muonDecayTimeMin/ns<<" ns , muonDecayTimeMax="<<muonDecayTimeMax/ns
// <<" ns , muonMeanLife="<<muonMeanLife/ns<<" ns."<<G4endl;
// find the primary muon
G4PrimaryParticle* generatedMuon = anEvent->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="<<decaytime/ns<<"ns."<< G4endl;
generatedMuon->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="<<x<<", y="<<y<<", z="<<z<<G4endl;
G4cout<<" px="<<px<<", py="<<py<<", pz="<<pz<<", xpolaris="<<xpolaris<<", ypolaris="<<ypolaris<<", zpolaris="<<zpolaris<<G4endl;
G4cout<<" numberOfGeneratedEvents="<<numberOfGeneratedEvents<<G4endl;
G4cout<<" ------------------------------------"<<G4endl;
}
}
//===============================================================================
void musrPrimaryGeneratorAction::SetInitialMuonPolariz(G4ThreeVector vIniPol)
{
G4double magnitude=vIniPol.mag();
if(magnitude<0.00000001) {
G4cout<< "Unpolarised initial muons"<<G4endl;
UnpolarisedMuonBeam=true;
if ((magnitude<0.0000000085)&&(magnitude>0.0000000075)) {
G4cout<< "Transversaly unpolarised initial muons"<<G4endl;
TransversalyUnpolarisedMuonBeam=true;
}
}
else {
xPolarisIni=vIniPol(0)/magnitude;
yPolarisIni=vIniPol(1)/magnitude;
zPolarisIni=vIniPol(2)/magnitude;
G4cout<< "Initial Muon Polarisation set to ("<<xPolarisIni<<","<<yPolarisIni<<","<<zPolarisIni<<")"<<G4endl;
}
}
//===============================================================================
void musrPrimaryGeneratorAction::SetMuonDecayTimeLimits(G4ThreeVector decayTimeLimits) {
muonDecayTimeMin = decayTimeLimits[0];
muonDecayTimeMax = decayTimeLimits[1];
muonMeanLife = decayTimeLimits[2];
// store the muon decay time parameters to the Root output
musrRootOutput* myRootOutput = musrRootOutput::GetRootInstance();
myRootOutput->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."<<G4endl;
}
else {
char line[501];
for (Int_t i=0; i<lineNumberOfTurtleFile; i++) {
if (feof(fTurtleFile)) rewind(fTurtleFile);
fgets(line,500,fTurtleFile);
}
G4cout << "musrPrimaryGeneratorAction::SetTurtleInputFileToEventNo: Turtle input file will start at line no.:"
<< lineNumberOfTurtleFile <<G4endl;
}
}
//===============================================================================
void musrPrimaryGeneratorAction::SetOrReadTheRandomNumberSeeds(G4int eventID) {
if (eventID == nRndmEventToSaveSeeds) {
G4cout<<"musrPrimaryGeneratorAction::SetOrReadTheRandomNumberSeeds: S A V I N G R A N D O M N O. S E E D S"<<G4endl;
G4cout<<" (for even nr. "<<eventID<<")"<<G4endl;
G4RunManager::GetRunManager()->rndmSaveThisEvent();
boolPrintInfoAboutGeneratedParticles = true;
}
if (eventID == 0) {
if (setRandomNrSeedFromFile_RNDM) {
G4cout<<"musrPrimaryGeneratorAction::SetOrReadTheRandomNumberSeeds: Restoring random number seeds from file kamil.rndm"<<G4endl;
G4RunManager::GetRunManager()->RestoreRandomNumberStatus("kamil.rndm");
boolPrintInfoAboutGeneratedParticles = true;
}
}
if (setRandomNrSeedFromFile) {
// G4cout<<"RandomNrInitialisers.size()="<<RandomNrInitialisers->size()<<G4endl;
if (eventID < int(pointerToSeedVector->size())) {
G4cout <<"musrEventAction.cc: seed will be set to="<< pointerToSeedVector->at(eventID)<<G4endl;
CLHEP::HepRandom::setTheSeed(pointerToSeedVector->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="<<thisEventNr;
CLHEP::HepRandom::setTheSeed(eventID);
// G4cout <<" getTheSeed="<<CLHEP::HepRandom::getTheSeed()<< G4endl;
CLHEP::RandGauss::setFlag(false);
}
}
void musrPrimaryGeneratorAction::SetKEnergy(G4double val) {
G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
G4double mu_mass = particleTable->FindParticle("mu+")->GetPDGMass();
p0=std::sqrt(val*val + 2*mu_mass*val);
// G4cout<<"musrPrimaryGeneratorAction::SetKEnergy: Muon kinetic energy of "
// <<val<<" MeV requested ==> initial muon momentum set to "<<p0<<" MeV/c"<<G4endl;
}

View File

@ -0,0 +1,177 @@
#include "musrPrimaryGeneratorMessenger.hh"
#include "musrPrimaryGeneratorAction.hh"
#include "G4UIcmdWithAString.hh"
#include "G4UIcmdWithADoubleAndUnit.hh"
#include "G4UIcmdWithADouble.hh"
#include "G4UIcmdWithAnInteger.hh"
#include "G4UIcmdWith3Vector.hh"
#include "G4UIcmdWith3VectorAndUnit.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
musrPrimaryGeneratorMessenger::musrPrimaryGeneratorMessenger(musrPrimaryGeneratorAction* musrGun)
:musrAction(musrGun)
{
setvertexCmd = new G4UIcmdWith3VectorAndUnit("/gun/vertex",this);
setvertexCmd->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....

87
src/musrQuadrupole.cc Normal file
View File

@ -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"<<G4endl;
G4cout << " Field fringeDepth set to " << fringeDepth/mm << " mm"<<G4endl;
G4cout << " Field fringeMaxZ set to " << fringeMaxZ/mm << " mm"<<G4endl;
G4cout << "\n-----------------------------------------------------------" << G4endl;
}
void musrQuadrupole::addFieldValue(const G4double point[4], G4double *field ) const {
G4ThreeVector global(point[0],point[1],point[2]);
G4ThreeVector local;
local = global2local.TransformPoint(global);
G4double r = sqrt(local[0]*local[0]+local[1]*local[1]);
if (r > 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: ("<<field[0]/tesla<<","<<field[1]/tesla<<","<<field[2]/tesla<<")"<<G4endl;
}
G4double musrQuadrupole::GetNominalFieldValue() {
return gradient;
}
void musrQuadrupole::SetNominalFieldValue(G4double newFieldValue) {
// // Rescale the magnetic field for a new value of the magnetic field
gradient=newFieldValue;
G4cout<<"musrQuadrupole.cc: gradient changed to="<< gradient/(tesla/m)<<" T/m"<<G4endl;
}

446
src/musrRootOutput.cc Normal file
View File

@ -0,0 +1,446 @@
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
#include "musrRootOutput.hh"
#include "G4RunManager.hh"
#include "G4Run.hh"
#include "musrErrorMessage.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
musrRootOutput::musrRootOutput() {
pointerToRoot=this;
boolIsAnySpecialSaveVolumeDefined=false;
nFieldNomVal=0;
ProcessIDMapping["DecayWithSpin"]=1;
ProcessIDMapping["eIoni"]=2;
ProcessIDMapping["eBrem"]=3;
ProcessIDMapping["annihil"]=4;
ProcessIDMapping["LowEnCompton"]=5;
ProcessIDMapping["LowEnConversion"]=6;
ProcessIDMapping["LowEnBrem"]=7;
ProcessIDMapping["LowEnergyIoni"]=8;
ProcessIDMapping["LowEnPhotoElec"]=9;
ProcessIDMapping["RadioactiveDecay"]=10;
ProcessIDMapping["muIoni"]=11;
ProcessIDMapping["MuFormation"]=12;
ProcessIDMapping["Decay"]=13;
ProcessIDMapping["initialParticle"]=100;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
musrRootOutput::~musrRootOutput() {}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
musrRootOutput* musrRootOutput::pointerToRoot=0;
musrRootOutput* musrRootOutput::GetRootInstance() {
return pointerToRoot;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4bool musrRootOutput::store_runID = true;
G4bool musrRootOutput::store_eventID = true;
G4bool musrRootOutput::store_weight = true;
G4bool musrRootOutput::store_BFieldAtDecay = true;
G4bool musrRootOutput::store_muIniPosX = true;
G4bool musrRootOutput::store_muIniPosY = true;
G4bool musrRootOutput::store_muIniPosZ = true;
G4bool musrRootOutput::store_muIniMomX = true;
G4bool musrRootOutput::store_muIniMomY = true;
G4bool musrRootOutput::store_muIniMomZ = true;
G4bool musrRootOutput::store_muIniPolX = true;
G4bool musrRootOutput::store_muIniPolY = true;
G4bool musrRootOutput::store_muIniPolZ = true;
G4bool musrRootOutput::store_muDecayDetID= true;
G4bool musrRootOutput::store_muDecayPosX = true;
G4bool musrRootOutput::store_muDecayPosY = true;
G4bool musrRootOutput::store_muDecayPosZ = true;
G4bool musrRootOutput::store_muDecayTime = true;
G4bool musrRootOutput::store_muDecayPolX = true;
G4bool musrRootOutput::store_muDecayPolY = true;
G4bool musrRootOutput::store_muDecayPolZ = true;
G4bool musrRootOutput::store_muTargetTime = false;
G4bool musrRootOutput::store_muTargetPolX = false;
G4bool musrRootOutput::store_muTargetPolY = false;
G4bool musrRootOutput::store_muTargetPolZ = false;
G4bool musrRootOutput::store_muM0Time = false;
G4bool musrRootOutput::store_muM0PolX = false;
G4bool musrRootOutput::store_muM0PolY = false;
G4bool musrRootOutput::store_muM0PolZ = false;
G4bool musrRootOutput::store_muM1Time = false;
G4bool musrRootOutput::store_muM1PolX = false;
G4bool musrRootOutput::store_muM1PolY = false;
G4bool musrRootOutput::store_muM1PolZ = false;
G4bool musrRootOutput::store_muM2Time = false;
G4bool musrRootOutput::store_muM2PolX = false;
G4bool musrRootOutput::store_muM2PolY = false;
G4bool musrRootOutput::store_muM2PolZ = false;
G4bool musrRootOutput::store_posIniMomX = true;
G4bool musrRootOutput::store_posIniMomY = true;
G4bool musrRootOutput::store_posIniMomZ = true;
G4bool musrRootOutput::store_det_ID = true;
G4bool musrRootOutput::store_det_edep = true;
G4bool musrRootOutput::store_det_edep_el = true;
G4bool musrRootOutput::store_det_edep_pos = true;
G4bool musrRootOutput::store_det_edep_gam = true;
G4bool musrRootOutput::store_det_edep_mup = true;
G4bool musrRootOutput::store_det_nsteps = true;
G4bool musrRootOutput::store_det_length = true;
G4bool musrRootOutput::store_det_start = true;
G4bool musrRootOutput::store_det_end = true;
G4bool musrRootOutput::store_det_x = true;
G4bool musrRootOutput::store_det_y = true;
G4bool musrRootOutput::store_det_z = true;
G4bool musrRootOutput::store_det_kine = true;
G4bool musrRootOutput::store_det_VrtxKine = true;
G4bool musrRootOutput::store_det_VrtxX = true;
G4bool musrRootOutput::store_det_VrtxY = true;
G4bool musrRootOutput::store_det_VrtxZ = true;
G4bool musrRootOutput::store_det_VrtxVolID = true;
G4bool musrRootOutput::store_det_VrtxProcID = true;
G4bool musrRootOutput::store_det_VrtxTrackID = true;
G4bool musrRootOutput::store_det_VrtxParticleID = true;
G4bool musrRootOutput::store_det_VvvKine = true;
G4bool musrRootOutput::store_det_VvvX = true;
G4bool musrRootOutput::store_det_VvvY = true;
G4bool musrRootOutput::store_det_VvvZ = true;
G4bool musrRootOutput::store_det_VvvVolID = true;
G4bool musrRootOutput::store_det_VvvProcID = true;
G4bool musrRootOutput::store_det_VvvTrackID = true;
G4bool musrRootOutput::store_det_VvvParticleID = true;
G4bool musrRootOutput::store_fieldNomVal = true;
G4bool musrRootOutput::store_fieldIntegralBx = false;
G4bool musrRootOutput::store_fieldIntegralBy = false;
G4bool musrRootOutput::store_fieldIntegralBz = false;
G4bool musrRootOutput::store_fieldIntegralBz1 = false;
G4bool musrRootOutput::store_fieldIntegralBz2 = false;
G4bool musrRootOutput::store_fieldIntegralBz3 = false;
G4int musrRootOutput::oldEventNumberInG4EqEMFieldWithSpinFunction=-1;
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void musrRootOutput::BeginOfRunAction() {
G4cout << "musrRootOutput::BeginOfRunAction() Defining the Root tree and branches:"<<G4endl;
G4int tmpRunNr=(G4RunManager::GetRunManager())->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."<<G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void musrRootOutput::EndOfRunAction() {
G4cout << "musrRootOutput::EndOfRunAction() - Writing out the Root tree:"<<G4endl;
rootTree->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; i<maxNGeantParameters; i++) {
TVector_GeantParametersD[i]=GeantParametersD[i];
}
TVector_GeantParametersD.Write("geantParametersD");
rootFile->Close();
G4cout<<"musrRootOutput::EndOfRunAction() - Root tree written out."<<G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void musrRootOutput::FillEvent() {
htest5->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 (i<maxNFieldnNominalValues) {
// cks the following will probably not be correct for electric field,
// because the units are tesla. Should be modified.
fieldNomVal[i]=value/tesla;
}
else {
char message[200];
sprintf(message,
"musrRootOutput.cc::SetFieldNomVal(): more electromagnetic fields then allowed: maxNFieldnNominalValues=%i",
maxNFieldnNominalValues);
musrErrorMessage::GetInstance()->musrError(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;
}
}

100
src/musrRunAction.cc Normal file
View File

@ -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: ----------------"<<G4endl;
FieldList::iterator i;
for (i=fields->begin(); i!=fields->end(); ++i) {
(*i)->construct();
// G4cout<<"\t==> "<<(*i)->GetElementFieldName()<<G4endl;
// 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++;
}
G4cout<<"-----------------------------------------------------------------"<<G4endl;
}
}
// Print out the field values at the points user requested to be printed out:
F04GlobalField::getObject()->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:"<<G4endl;
G4cout << " Number of events = " << aRun->GetNumberOfEvent()<<G4endl;
// << " " << *timer << G4endl;
G4cout << " User elapsed time = "<<timer->GetUserElapsed()/3600<<"h = "
<<timer->GetUserElapsed()/60<<"min = "<<timer->GetUserElapsed()<<"s."<<G4endl;
G4cout << " Real elapsed time = "<<timer->GetRealElapsed()/3600<<"h = "
<<timer->GetRealElapsed()/60<<"min = "<<timer->GetRealElapsed()<<"s."<<G4endl;
G4cout << " System elapsed time = "<<timer->GetSystemElapsed()/3600<<"h = "
<<timer->GetSystemElapsed()/60<<"min = "<<timer->GetSystemElapsed()<<"s."<<G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

156
src/musrScintHit.cc Normal file
View File

@ -0,0 +1,156 @@
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
#include "musrScintHit.hh"
#include "G4UnitsTable.hh"
#include "G4VVisManager.hh"
#include "G4Circle.hh"
#include "G4Colour.hh"
#include "G4VisAttributes.hh"
#include "G4ios.hh"
#include "G4MagneticField.hh"
#include "G4FieldManager.hh"
#include "G4TransportationManager.hh"
#include "globals.hh"
#include "G4Transform3D.hh"
#include "G4ProcessManager.hh"
#include "G4Track.hh"
#include "G4ThreeVector.hh"
#include "G4RunManager.hh"
#include "G4Run.hh"
#include <fstream>
#include <iostream>
#include <iomanip>
G4Allocator<musrScintHit> 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()"<<G4endl;
G4RunManager* fRunManager = G4RunManager::GetRunManager();
eventID = fRunManager->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<<" "<<pos.y()/cm <<" "<< pos.z()/cm <<G4endl;
// G4cout << "Field is "<< B[2]<<G4endl;
std::ofstream posfile1;
posfile1.open ("scint.dat", std::ios::out | std::ios::app);
posfile1 << runID << " " << eventID
<< " " << logicalVolume
<< " " << ScintMultihitSwitch
<<" " << edep
<< " " << fabs(B[2])
<<" "<< pre_pos.x()/cm<<" "<<pre_pos.y()/cm <<" "<< pre_pos.z()/cm
<< " " << globalTime/s
// << " " << IBchamberNb
// << " first=" << firstStepInVolume << " last=" << lastStepInVolume
<< G4endl;
posfile1.close();
}
eventIDoldScint=eventID;
runIDoldScint = runID;
// ScintChamberNbold = IBchamberNb;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

359
src/musrScintSD.cc Normal file
View File

@ -0,0 +1,359 @@
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
#include "musrScintSD.hh"
#include "G4HCofThisEvent.hh"
#include "G4Step.hh"
#include "G4ThreeVector.hh"
#include "G4SDManager.hh"
#include "G4ios.hh"
#include <algorithm> // 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 <vector>
//bool myREMOVEfunction (int i,int j) { return (i<j); }
//bool timeOrdering (musrScintHit hit1, musrScintHit hit2) {
// return (hit1.GetGlobalTime()<hit2.GetGlobalTime());
//}
//
//bool timeOrdering2 (std::map<int,double>::iterator i1, std::map<int,double>::iterator m2) {
// return ( (*i1).first()<(*i2).second() );
//}
//
//bool timeOrdering2 (std::pair<int,double> p1, std::pair<int,double> p2) {
// return ( p1.first()<p2.second() );
//}
//
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
musrScintSD::musrScintSD(G4String name)
:G4VSensitiveDetector(name)
{
G4String HCname;
collectionName.insert(HCname="scintCollection");
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
musrScintSD::~musrScintSD(){ }
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void musrScintSD::Initialize(G4HCofThisEvent* HCE) {
if (verboseLevel>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="<<HCID<<"\n";
}
HCE->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"<<G4endl;
G4int NbHits = scintCollection->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; i<NbHits; i++) {
musrScintHit* aHit = (*scintCollection)[i];
G4String aHitVolumeName = aHit->GetLogVolName();
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<G4double,G4int> 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<G4double,G4int>::iterator it;
for (G4int i=0; i<NbHits; i++) {
musrScintHit* aHit = (*scintCollection)[i];
G4double tmptime=aHit->GetGlobalTime();
// G4cout<<"Hit nr "<<i<<" at time="<<tmptime<<" with edep="<<aHit->GetEdep()/MeV
// <<" detID="<<myRootOutput->ConvertVolumeToID(aHit->GetLogVolName())<< G4endl;
myHitTimeMapping.insert ( std::pair<G4double,G4int>(tmptime,i) );
}
// Loop over all hits (which are sorted according to their time):
G4int nSignals=0;
for (it=myHitTimeMapping.begin(); it!=myHitTimeMapping.end(); it++) {
// G4cout << "Key:" << it->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; j<nSignals; j++) {
if ( (aHitVolumeID==det_ID[j]) && ((aHitTime-det_time_end[j])<mySignalSeparationTime) ) {
signalAssigned=true;
det_edep[j] += aHit->GetEdep();
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<G4double,G4int> mySignalMapping;
std::map<G4double,G4int>::iterator itt;
for (G4int i=0; i<nSignals; i++) {
mySignalMapping.insert ( std::pair<G4double,G4int>(-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"<<G4endl;
vvvLogVolID=myRootOutput->ConvertVolumeToID(vvvLogVol);
}
else {
G4cout<<" oldTrackRetrievedOK is false"<<G4endl;
oldTrackID = -999;
vvvParentTrackID = -999;
vvvPparticleID = -999;
vvvKine = -999;
vvvPosition = G4ThreeVector(-999,-999,-999);
vvvLogVol = "undefined";
vvvProcess = "undefined";
}
} while (oldTrackRetrievedOK && (vvvLogVolID==det_ID[ii]));
if (oldTrackRetrievedOK) {
G4int vvvProcessID=myRootOutput->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......

443
src/musrSteppingAction.cc Normal file
View File

@ -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"<<G4endl;
radioactiveElectronAlreadySavedInThisEvent=false;
muAlreadyWasInTargetInThisEvent=false;
muAlreadyWasInM0InThisEvent=false;
muAlreadyWasInM1InThisEvent=false;
muAlreadyWasInM2InThisEvent=false;
myOldTracksMap.clear();
indexOfOldTrack = -1;
realTimeWhenThisEventStarted=time(0);
BxIntegral=0; ByIntegral=0; BzIntegral=0; BzIntegral1=0; BzIntegral2=0; BzIntegral3=0;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void musrSteppingAction::UserSteppingAction(const G4Step* aStep) {
G4Track* aTrack = aStep->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 "<<fRunManager->GetCurrentEvent()->GetEventID()
<<" aborted because calculation took already 60 seconds."<<G4endl;
musrErrorMessage::GetInstance()->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.:"<<fRunManager->GetCurrentEvent()->GetEventID()
<<", the particle \""<< aTrack->GetDynamicParticle()->GetDefinition()->GetParticleName()
<<"\" has energy of "<<(aStep->GetPreStepPoint()->GetKineticEnergy())/GeV<<" GeV."<<G4endl;
G4cout<<" Deleting the event!"<<G4endl;
G4cout.flush();
myRootOutput->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<G4int,G4int>::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<G4int,G4int>(trackID,indexOfOldTrack) );
if (indexOfOldTrack<maxNumberOfOldTracks) {
particleID_oldTrack[indexOfOldTrack] = aTrack->GetDefinition()->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="<<BzIntegral<<" stepLength="<<stepLength<<"FieldForFieldIntegral[2]="<<FieldForFieldIntegral[2]<<G4endl;
}
}
// Pick up process "DecayWithSpin":
const G4VProcess* process = aStep->GetPostStepPoint()->GetProcessDefinedStep();
if (process!=NULL) {
G4String processName = process->GetProcessName();
if (processName=="DecayWithSpin") {
// std::cout<<"musrSteppingAction: DecayWithSpin"<<std::endl;
musrParameters::field_DecayWithSpin=true;
// Test whether the event reweighting is requeseted for this volume
// (i.e. user may request reweighting of events depending on the volume,
// in which the muon stops and decays).
if (boolMuonEventReweighting) {
G4int weight = volumeMuonWeightMapping[actualVolume];
if (weight!=0) {
G4double randomNumber = weight * G4UniformRand();
if (randomNumber < (weight-1.)) {
// G4cout<<"Event will be aborted"<<G4endl;
musrErrorMessage::GetInstance()->musrError(INFO,
"musrSteppingAction: event deleted because of the reweighting.",true);
G4RunManager* fRunManager = G4RunManager::GetRunManager();
weight=0;
fRunManager->AbortEvent();
}
// else {
// G4cout<<"Event will be reweighted"<<G4endl;
// }
myRootOutput->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"<<G4endl;
if (fMgr!=NULL) {
// G4cout<<"Debug 2"<<G4endl;
if(!fMgr->DoesFieldChangeEnergy()) { //then we have a magnetic field
// G4cout<<"Debug 3"<<G4endl;
fMgr->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 = "<<BzIntegral<<G4endl;
// store the information about the emerging positron
G4TrackVector* secondary = fpSteppingManager->GetSecondary();
G4int n_secondaries= (*secondary).size();
for (G4int i=0; i<n_secondaries; i++) {
if ( ((*secondary)[i]->GetDefinition()->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="<<trackID<<"\t myOldTracksMap[trackID]="<<myOldTracksMap[trackID]<<G4endl;
std::map<G4int,G4int>::iterator itr;
itr = myOldTracksMap.find(trackID);
if ( itr==myOldTracksMap.end() ) {
// if ((ind==0)||(ind>=maxNumberOfOldTracks)) {
char eMessage[200];
sprintf(eMessage,"musrSteppingAction::GetInfoAboutOldTrack: trackID not found in myOldTracksMap, det_VvvXXX variables might be affected");
musrErrorMessage::GetInstance()->musrError(WARNING,eMessage,false);
G4cout<<" Requested trackID="<<trackID<<G4endl;
// G4cout<<"Saved tracks:"<<G4endl;
// for (itr=myOldTracksMap.begin(); itr!=myOldTracksMap.end(); itr++) {
// G4cout<<"first="<<itr->first<<"\tsecond="<<itr->second<<G4endl;
// }
return false;
}
else {
G4int ind = itr->second;
if (ind>=maxNumberOfOldTracks) {
G4cout<<"musrSteppingAction::GetInfoAboutOldTrack: Problem! ind>maxNumberOfOldTracks! ("<<ind<<">"<<maxNumberOfOldTracks<<")"<<G4endl;
G4cout<<" itr->first = "<<itr->first<<", trackID = "<<trackID<<G4endl;
return false;
}
parentTrackID=parentTrackID_oldTrack[ind];
if (trackID==parentTrackID) {
G4cout<<"musrSteppingAction::GetInfoAboutOldTrack: Problem! trackID==parentTrackID! ("<<trackID<<"=="<<parentTrackID<<")"<<G4endl;
return false;
}
particleID=particleID_oldTrack[ind];
vertexKine=vertexKine_oldTrack[ind];
vertexPosition= vertexPosition_oldTrack[ind];
vertexLogVol=vertexLogVol_oldTrack[ind];
vertexProcess=vertexProcess_oldTrack[ind];
}
// G4cout<<"GetInfoAboutOldTrack: trackID="<<trackID<<"\t parentTrackID="<<parentTrackID<<"\t particleID="<<particleID;
// G4cout<<"\t vertexKine="<<vertexKine<<"\t vertexLogVol="<<vertexLogVol<<"\t vertexProcess="<<vertexProcess<<G4endl;
return true;
}
G4bool musrSteppingAction::AreTracksCommingFromSameParent(G4int trackID1, G4int trackID2, G4String volumeName){
// There are two tracks with different track IDs. This routine finds the parents of both of them,
// which were created outside logical volume "volumeID". If both tracks have the same parent, the
// functions returns "true".
std::map<G4int,G4int>::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 ="<<trackID1<<" not found"<<G4endl;
return false;
}
ind = itr->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 ="<<trackID2<<" not found"<<G4endl;
return false;
}
ind = itr->second;
trID = parentTrackID_oldTrack[ind];
} while (vertexLogVol_oldTrack[ind]==volumeName);
if (track1==track2) {return true;}
//G4cout<<"track1="<<track1<<"\ttrack2="<<track2<<G4endl; return true;}
// G4cout<<"\t\t\t\ttrack1="<<track1<<"\ttrack2="<<track2<<G4endl;
return false;
}

151
src/musrSteppingVerbose.cc Normal file
View File

@ -0,0 +1,151 @@
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
#include "musrSteppingVerbose.hh"
#include "G4SteppingManager.hh"
#include "G4UnitsTable.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
musrSteppingVerbose::musrSteppingVerbose()
{}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
musrSteppingVerbose::~musrSteppingVerbose()
{}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void musrSteppingVerbose::StepInfo()
{
CopyState();
G4int prec = G4cout.precision(3);
if( verboseLevel >= 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......

View File

@ -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 "<<fieldTableType<<") set to "<< fieldValue/fieUnit << " "<< fUnit << G4endl;
G4cout << "\n ---> " "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) !!!"<<G4endl;
musrErrorMessage::GetInstance()->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.): "<<fldType<<"x, "<<fldType<<"y, "<<fldType<<"z"<<G4endl;
boolMinimaAndMaximaDefinedInTheFile = true;
minimumx = minimumx * lenUnit;
minimumy = minimumy * lenUnit;
minimumz = minimumz * lenUnit;
maximumx = maximumx * lenUnit;
maximumy = maximumy * lenUnit;
maximumz = maximumz * lenUnit;
}
else {
G4cout << " ---> Assumed order (6 col.): x, y, z, "<<fldType<<"x, "<<fldType<<"y, "<<fldType<<"z"<<G4endl;
}
// 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,"3D")==0)||(strcmp(fieldTableType,"3DBOpera")==0)) {
// OPERA format of the input file:
// Read table dimensions
lenUnit = 1*m;
fieldNormalisation = 1.;
G4cout << "3D, field-map file format from OPERA (Kamil)" << G4endl;
G4cout << " ---> Assumed order (7 col.): x, y, z, "<<fldType<<"x, "<<fldType<<"y, "<<fldType<<"z, Dummy"<<G4endl;
file.getline(buffer,256); // Skip the first empty line of the file
file >> 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, "<<fldType<<"r, "<<fldType<<"z"<<G4endl;
char lenUnitFromFile[50];
file >> 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, "<<fldType<<"r, "<<fldType<<"z, Dummy"<<G4endl;
file >> 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, "<<fldType<<"r, "<<fldType<<"z, Dummy"<<G4endl;
file >> nx >> nDummy >> nz;
// G4cout << nx <<" "<< nDummy <<" "<< nz<<G4endl;
do {
file.getline(buffer,256);
} while ( buffer[1]!='0');
}
else {
G4cout << " musrTabulatedElementField::musrTabulatedElementField: Unknown field required!"
<< " ("<<fieldTableType<<")" << G4endl;
G4cout << " =====> 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; ix<nx; ix++) {
xField[ix].resize(ny);
yField[ix].resize(ny);
zField[ix].resize(ny);
for (iy=0; iy<ny; iy++) {
xField[ix][iy].resize(nz);
yField[ix][iy].resize(nz);
zField[ix][iy].resize(nz);
}
}
}
else if (fldDim==2) {
G4cout << " The grid consists of [" << nx << " x " << nz << "] R, z values" << G4endl;
G4cout << " Field map normalisation factor = " << fieldNormalisation << G4endl;
G4cout << " Field map length unit = " << lenUnit << G4endl;
if ((nx<2)||(nz<2)) {
char eMessage[200];
sprintf(eMessage,"musrTabulatedElementField(): Strange Field table! nx=%i, nz=%i",nx,nz);
musrErrorMessage::GetInstance()->musrError(WARNING,eMessage,false);
}
// Set up storage space for the table
xField2D.resize( nx );
zField2D.resize( nx );
for (ix=0; ix<nx; ix++) {
xField2D[ix].resize(nz);
zField2D[ix].resize(nz);
}
}
// Read in the data
double xval,yval,zval,bx,by,bz;
double permeability; // Not used in this example.
for (ix=0; ix<nx; ix++) {
for (iy=0; iy<ny; iy++) {
for (iz=0; iz<nz; iz++) {
if ((strcmp(fieldTableType,"3DE")==0)||(strcmp(fieldTableType,"3DB")==0)) {
if (boolMinimaAndMaximaDefinedInTheFile) {
file >> 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 <<G4endl;
}
else if (strcmp(fieldTableType,"2D_OperaXY")==0) {
file >> xval >> zval >> yval >> bx >> bz >> permeability;
}
else {
G4cout << " musrTabulatedElementField::musrTabulatedElementField: Undefined field required!"
<< " ("<<fieldTableType<<")" << G4endl;
G4cout << " =====> 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 "<<G4endl;
if (fldDim==3) G4cout<<" ---> 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:"<<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 "<<G4endl;
if (fldDim==3) G4cout<<" ---> 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."<<G4endl;
G4cout << "-----------------------------------------------------------" << G4endl;
// Set maximum width, height and lenght of the field - very important! This
// dimensions are used to decide whether the "addFieldValue" method will be
// called at all for a given elementField.
if (fldDim==2) {
maximumWidth = 2*dx;
maximumHeight = 2*dx;
if ( (strcmp(fieldTableType,"2D")==0)||(strcmp(fieldTableType,"2DBOpera")==0)||(strcmp(fieldTableType,"2D_OperaXY")) ) {
maximumLength = 2*dz;
}
else maximumLength = dz;
}
else {
maximumWidth = dx;
maximumHeight = dy;
maximumLength = dz;
}
}
void musrTabulatedElementField::addFieldValue(const G4double point[4],
G4double *field ) const
{
// G4cout<<"musrTabulatedElementField::addFieldValue"<<G4endl;
if (fldDim==2) addFieldValue2D(point,field);
else addFieldValue3D(point,field);
}
void musrTabulatedElementField::addFieldValue3D(const G4double point[4],
G4double *field ) const
{
G4double B[3]; // Field value obtained from the field table
G4ThreeVector global(point[0],point[1],point[2]);
G4ThreeVector local;
local = global2local.TransformPoint(global);
double x = local.x();
double y = local.y();
double z = local.z();
// G4cout<<"Global points= "<<point[0]<<", "<<point[1]<<", "<<point[2]<<", Local point= "<<x<<", "<<y<<", "<<z<<G4endl;
// Check that the point is within the defined region
if ( x>minimumx && x<maximumx &&
y>minimumy && y<maximumy &&
z>minimumz && z<maximumz ) {
// Position of given point within region, normalized to the range
// [0,1]
double xfraction = (x - minimumx) / dx;
double yfraction = (y - minimumy) / dy;
double zfraction = (z - minimumz) / dz;
// Need addresses of these to pass to modf below.
// modf uses its second argument as an OUTPUT argument.
double xdindex, ydindex, zdindex;
// Position of the point within the cuboid defined by the
// nearest surrounding tabulated points
double xlocal = ( modf(xfraction*(nx-1), &xdindex));
double ylocal = ( modf(yfraction*(ny-1), &ydindex));
double zlocal = ( modf(zfraction*(nz-1), &zdindex));
// The indices of the nearest tabulated point whose coordinates
// are all less than those of the given point
int xindex = static_cast<int>(xdindex);
int yindex = static_cast<int>(ydindex);
int zindex = static_cast<int>(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="<<xindex<<" x="<<x<<" xfraction="<<xfraction<<std::endl;
if (xindex<0) xindex=0;
else xindex=nx-2;
}
if ((yindex<0)||(yindex>(ny-2))) {
std::cout<<"SERIOUS PROBLEM: yindex out of range! yindex="<<yindex<<" y="<<y<<" yfraction="<<yfraction<<std::endl;
if (yindex<0) yindex=0;
else yindex=ny-2;
}
if ((zindex<0)||(zindex>(nz-2))) {
std::cout<<"SERIOUS PROBLEM: zindex out of range! zindex="<<zindex<<" z="<<z<<" zfraction="<<zfraction<<std::endl;
if (zindex<0) zindex=0;
else zindex=nz-2;
}
// Full 3-dimensional version
B[0] =
xField[xindex ][yindex ][zindex ] * (1-xlocal) * (1-ylocal) * (1-zlocal) +
xField[xindex ][yindex ][zindex+1] * (1-xlocal) * (1-ylocal) * zlocal +
xField[xindex ][yindex+1][zindex ] * (1-xlocal) * ylocal * (1-zlocal) +
xField[xindex ][yindex+1][zindex+1] * (1-xlocal) * ylocal * zlocal +
xField[xindex+1][yindex ][zindex ] * xlocal * (1-ylocal) * (1-zlocal) +
xField[xindex+1][yindex ][zindex+1] * xlocal * (1-ylocal) * zlocal +
xField[xindex+1][yindex+1][zindex ] * xlocal * ylocal * (1-zlocal) +
xField[xindex+1][yindex+1][zindex+1] * xlocal * ylocal * zlocal ;
B[1] =
yField[xindex ][yindex ][zindex ] * (1-xlocal) * (1-ylocal) * (1-zlocal) +
yField[xindex ][yindex ][zindex+1] * (1-xlocal) * (1-ylocal) * zlocal +
yField[xindex ][yindex+1][zindex ] * (1-xlocal) * ylocal * (1-zlocal) +
yField[xindex ][yindex+1][zindex+1] * (1-xlocal) * ylocal * zlocal +
yField[xindex+1][yindex ][zindex ] * xlocal * (1-ylocal) * (1-zlocal) +
yField[xindex+1][yindex ][zindex+1] * xlocal * (1-ylocal) * zlocal +
yField[xindex+1][yindex+1][zindex ] * xlocal * ylocal * (1-zlocal) +
yField[xindex+1][yindex+1][zindex+1] * xlocal * ylocal * zlocal ;
B[2] =
zField[xindex ][yindex ][zindex ] * (1-xlocal) * (1-ylocal) * (1-zlocal) +
zField[xindex ][yindex ][zindex+1] * (1-xlocal) * (1-ylocal) * zlocal +
zField[xindex ][yindex+1][zindex ] * (1-xlocal) * ylocal * (1-zlocal) +
zField[xindex ][yindex+1][zindex+1] * (1-xlocal) * ylocal * zlocal +
zField[xindex+1][yindex ][zindex ] * xlocal * (1-ylocal) * (1-zlocal) +
zField[xindex+1][yindex ][zindex+1] * xlocal * (1-ylocal) * zlocal +
zField[xindex+1][yindex+1][zindex ] * xlocal * ylocal * (1-zlocal) +
zField[xindex+1][yindex+1][zindex+1] * xlocal * ylocal * zlocal ;
B[0] *= ffieldValue;
B[1] *= ffieldValue;
B[2] *= ffieldValue;
G4ThreeVector finalField(B[0],B[1],B[2]);
finalField = global2local.Inverse().TransformAxis(finalField);
if (fldType == 'E') {
field[3] += finalField.x();
field[4] += finalField.y();
field[5] += finalField.z();
}
else {
field[0] += finalField.x();
field[1] += finalField.y();
field[2] += finalField.z();
}
}
// G4cout<<"Kamil: Field: ("<<field[0]/tesla<<","<<field[1]/tesla<<","<<field[2]/tesla<<")"<<G4endl;
}
void musrTabulatedElementField::addFieldValue2D(const G4double point[4],
G4double *field ) const
{
G4double B[3]; // Field value obtained from the field table
G4ThreeVector global(point[0],point[1],point[2]);
G4ThreeVector local;
local = global2local.TransformPoint(global);
double x, z, z_sign;
if ((strcmp(fieldTableType,"2D")==0)||(strcmp(fieldTableType,"2DBOpera")==0)||
(strcmp(fieldTableType,"2D_OperaXY"))||(strcmp(fieldTableType,"2DEf")==0)) {
// Field is defined in just positive range of z; i.e. it is expected to be "symmetric"
// and the field for negative z is calculated from the positive z half.
x = sqrt(local.x()*local.x()+local.y()*local.y());
z = fabs(local.z());
z_sign = (local.z()>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 ( x<maximumx && z<maximumz ) {
// if (evNr>evNrKriz) std::cout<<"bol som tu"<<std::endl;
// Position of given point within region, normalized to the range
// [0,1]
double xfraction = (x - minimumx) / dx;
double zfraction = (z - minimumz) / dz;
// Need addresses of these to pass to modf below.
// modf uses its second argument as an OUTPUT argument.
double xdindex, zdindex;
// Position of the point within the cuboid defined by the
// nearest surrounding tabulated points
double xlocal = ( modf(xfraction*(nx-1), &xdindex));
double zlocal = ( modf(zfraction*(nz-1), &zdindex));
// The indices of the nearest tabulated point whose coordinates
// are all less than those of the given point
int xindex = static_cast<int>(xdindex);
int zindex = static_cast<int>(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="<<xindex<<" x="<<x<<" xfraction="<<xfraction<<std::endl;
if (xindex<0) xindex=0;
else xindex=nx-2;
}
if ((zindex<0)||(zindex>(nz-2))) {
std::cout<<"SERIOUS PROBLEM: zindex out of range! zindex="<<zindex<<" z="<<z<<" zfraction="<<zfraction<<std::endl;
if (zindex<0) zindex=0;
else zindex=nz-2;
}
// G4cout<<"xField2D["<<xindex<<"]["<<zindex<<"]="<<xField2D[xindex ][zindex ]<<G4endl;
// G4cout<<"zField2D["<<xindex<<"]["<<zindex<<"]="<<zField2D[xindex ][zindex ]<<G4endl;
// Interpolate between the neighbouring points
double Bfield_R =
xField2D[xindex ][zindex ] * (1-xlocal) * (1-zlocal) +
xField2D[xindex ][zindex+1] * (1-xlocal) * zlocal +
xField2D[xindex+1][zindex ] * xlocal * (1-zlocal) +
xField2D[xindex+1][zindex+1] * xlocal * zlocal ;
B[0] = (x>0) ? Bfield_R * (local.x() /x) : 0.;
B[1] = (x>0) ? Bfield_R * (local.y() /x) : 0.;
B[2] =
zField2D[xindex ][zindex ] * (1-xlocal) * (1-zlocal) +
zField2D[xindex ][zindex+1] * (1-xlocal) * zlocal +
zField2D[xindex+1][zindex ] * xlocal * (1-zlocal) +
zField2D[xindex+1][zindex+1] * xlocal * zlocal ;
if (fldType == 'E') { // Electric field
B[0] *= ffieldValue;
B[1] *= ffieldValue;
B[2] *= ffieldValue * z_sign;
}
else { // Magnetic field
B[0] *= ffieldValue * z_sign;
B[1] *= ffieldValue * z_sign;
B[2] *= ffieldValue;
}
G4ThreeVector finalField(B[0],B[1],B[2]);
finalField = global2local.Inverse().TransformAxis(finalField);
if (fldType == 'E') {
field[3] += finalField.x();
field[4] += finalField.y();
field[5] += finalField.z();
}
else {
field[0] += finalField.x();
field[1] += finalField.y();
field[2] += finalField.z();
}
// G4cout<<"F= "<<field[0]<<" "<<field[1]<<" "<<field[2]<<" "<<field[3]<<" "<<field[4]<<" "<<field[5]<<G4endl;
}
}
G4double musrTabulatedElementField::GetNominalFieldValue() {
return ffieldValue;
}
void musrTabulatedElementField::SetNominalFieldValue(G4double newFieldValue) {
// // Rescale the magnetic field for a new value of the magnetic field
ffieldValue=newFieldValue;
G4cout<<"musrTabulatedElementField.cc: ffieldValue changed to="<< ffieldValue/fieUnit<<" "<<fUnit<<G4endl;
}
void musrTabulatedElementField::Invert(const char* indexToInvert) {
// This function inverts the indexes of the field table for a given axis (x or z).
// It should be called in the case when the x or z coordinate in the initial
// field table is ordered in the decreasing order.
std::vector< std::vector< std::vector< double > > > 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!"<<G4endl;
G4cout<<"It has not been tested yet!"<<G4endl;
if (strcmp(indexToInvert,"x")==0) {invertX=true; std::swap(maximumx,minimumx);}
if (strcmp(indexToInvert,"y")==0) {invertY=true; std::swap(maximumx,minimumx);}
if (strcmp(indexToInvert,"z")==0) {invertZ=true; std::swap(maximumz,minimumz);}
for (int ix=0; ix<nx; ix++) {
for (int iy=0; iy<ny; iy++) {
for (int iz=0; iz<nz; iz++) {
if (invertX) {
xField[ix][iy][iz] = xFieldTemp[nx-1-ix][iy][iz];
yField[ix][iy][iz] = yFieldTemp[nx-1-ix][iy][iz];
zField[ix][iy][iz] = zFieldTemp[nx-1-ix][iy][iz];
}
else if(invertY) {
xField[ix][iy][iz] = xFieldTemp[ix][ny-1-iy][iz];
yField[ix][iy][iz] = yFieldTemp[ix][ny-1-iy][iz];
zField[ix][iy][iz] = zFieldTemp[ix][ny-1-iy][iz];
}
else if(invertZ) {
xField[ix][iy][iz] = xFieldTemp[ix][iy][nz-1-iz];
yField[ix][iy][iz] = yFieldTemp[ix][iy][nz-1-iz];
zField[ix][iy][iz] = zFieldTemp[ix][iy][nz-1-iz];
}
}
}
}
}

91
src/musrUniformField.cc Normal file
View File

@ -0,0 +1,91 @@
// Geant4 simulation for MuSR
// AUTHOR: Toni SHIROKA, Paul Scherrer Institut, PSI
// DATE : 2008-05
//
#include "globals.hh"
#include "G4GeometryManager.hh"
#include "musrUniformField.hh"
musrUniformField::musrUniformField(G4double EMF[6], G4double half_X, G4double half_Y, G4double half_Z, G4LogicalVolume* lv, G4ThreeVector c)
: F04ElementField(c, lv) {
// EMF[6] ... constant vector of the field: 3 components magnetic + 3 components electric field
// half_X, half_Y, half_Z ... half dimenstions of the box, within which the field is defined
for (int i = 0; i < 6; i++){
EMfield[i] = EMF[i];
}
fieldLength = 2.*half_Z;
fieldWidth = 2.*half_X;
fieldHeight = 2.*half_Y;
G4cout << "\n-----------------------------------------------------------"
<< "\n Uniform electromagnetic field"
<< G4endl;
G4String volName = lv->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);
}

107
src/yields.cc Normal file
View File

@ -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 <iomanip>
#include <fstream>
#include <iostream>
#include <stdlib.h>
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 <<std::endl;
// Abort in case of negative energies ---------------------------
if (E < 0)
{
std::cout<< "Error in method ''Yields'':" <<std::endl;
std::cout<< "E = "<< E <<" < 0!" <<std::endl;
std::cout<< "-> ABORTED!" <<std::endl;
return;
}
//---------------------------------------------------------------
// Definition of variables (aux_n are some auxiliary variables)
// Calculate energy in (classical) terms of speed (in units of v_Bohr):
v_rel = sqrt(2.*E/mass)/ v_Bohr;
aux1 = v_rel*v_rel;
aux2 = two_k_Fermi*v_rel;
Q_zero = 1. + (k_zero_Quad - k_Fermi_Quad - aux1) / aux2;
Q_minus = 1. + (k_minus_Quad - k_Fermi_Quad - aux1) / aux2;
aux1 = a_zero * Q_zero;
aux2 = a_minus * Q_minus;
aux3 = (1.-Q_zero)*(1.-Q_minus);
D = aux1*(aux2 + (1.-Q_minus)) + aux3;
Yield_minus = aux1*aux2 / D;
Yield_plus = aux3 / D;
Yield_minus = Yield_minus* exp(-vc_minus/v_rel);
Yield_plus = Yield_plus * exp(-vc_plus /v_rel);
if(Yield_minus > 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;
}