diff --git a/.gitignore b/.gitignore index 0b73577..185e453 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ *.o *.so src/G4fixes +src/G4debug .clone_done .link_to_fixes_done .make_done diff --git a/.sconsign.dblite b/.sconsign.dblite new file mode 100644 index 0000000..c34dd4c Binary files /dev/null and b/.sconsign.dblite differ diff --git a/GNUmakefile b/GNUmakefile index 0e6860f..410d24f 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -23,7 +23,7 @@ endif CPPFLAGS += -I$(HDDS_HOME) -I./src -I./src/G4fixes CPPFLAGS += -I./src/G4debug -CPPFLAGS += -I$(HALLD_HOME)/$(BMS_OSNAME)/include +CPPFLAGS += -I$(HALLD_RECON_HOME)/$(BMS_OSNAME)/include CPPFLAGS += -I$(JANA_HOME)/include CPPFLAGS += -I$(shell root-config --incdir) CPPFLAGS += -I/usr/include/Qt @@ -32,19 +32,24 @@ CPPFLAGS += -Wno-unused-parameter -Wno-unused-but-set-variable CPPFLAGS += -DUSE_SSE2 -std=c++11 #CPPFLAGS += -I/usr/include/Qt #CPPFLAGS += -DLINUX_CPUTIME_PROFILING=1 -#CPPFLAGS += -DCHECK_OVERLAPS_MM=1e-4 +#CPPFLAGS += -DCHECK_OVERLAPS_MM=1e-6 CPPFLAGS += -DBYPASS_DRAWING_CLIPPED_VOLUMES CPPFLAGS += -DLAYERED_GEOMETRY_PICKING_EXTENSIONS #CPPFLAGS += -DG4UI_USE_EXECUTIVE CPPFLAGS += -DG4VIS_BUILD_OPENGL_DRIVER CPPFLAGS += -DG4VIS_BUILD_OPENGLX_DRIVER CPPFLAGS += -DG4MULTITHREADED +#CPPFLAGS += -DVERBOSE_RANDOMS=1 #CPPFLAGS += -DFORCE_PARTICLE_TYPE_CHARGED_GEANTINO #CPPFLAGS += -DBP_DEBUG #CPPFLAGS += -DMOD_SPONCE #CPPFLAGS += -DDEBUG_PLACEMENT #CPPFLAGS += -DDEBUG_SECTIONPLANE #CPPFLAGS += -DDEBUG_SECTIONPLANE_ZAVE +#CPPFLAGS += -DG4VERSION_10_04_OR_LATER=1 +ifneq (, $(wildcard $(HALLD_RECON_HOME)/src/libraries/DIRC/DDIRCPmtHit.*)) + CPPFLAGS += -DDIRCTRUTHEXTRA +endif # If you want to build against Geant4.10.03 or greater, you will need this line uncommented #CPPFLAGS += -DG4VUSERPHYSICSLIST_HAS_GETPARTICLEITERATOR @@ -54,17 +59,19 @@ CPPVERBOSE = 1 #G4DEBUG = 1 hdgeant4_sources := $(filter-out src/CobremsGeneration.cc, $(wildcard src/*.cc)) +Cobrems_sources := $(wildcard src/Cobrems*.cc) G4fixes_sources := $(wildcard src/G4fixes/*.cc) G4debug_sources := $(wildcard src/G4debug/*.cc) HDDS_sources := $(HDDS_HOME)/XString.cpp $(HDDS_HOME)/XParsers.cpp $(HDDS_HOME)/hddsCommon.cpp ROOTLIBS = $(shell root-config --libs) -lGeom -lTMVA -lTreePlayer -DANALIBS = -L$(HALLD_HOME)/$(BMS_OSNAME)/lib -lHDGEOMETRY -lDANA \ - -lANALYSIS -lBCAL -lCCAL -lCDC -lCERE -lDIRC -lFCAL \ +DANALIBS = -L$(HALLD_RECON_HOME)/$(BMS_OSNAME)/lib -lHDGEOMETRY -lDANA \ + -lANALYSIS -lBCAL -lCCAL -lCDC -lCERE -lTRD -lDIRC -lFCAL \ -lFDC -lFMWPC -lHDDM -lPAIR_SPECTROMETER -lPID -lRF \ -lSTART_COUNTER -lTAGGER -lTOF -lTPOL -lTRACKING \ - -lTRIGGER -lDAQ -lTTAB -lEVENTSTORE -lKINFITTER \ + -lTRIGGER -lDAQ -lTTAB -lEVENTSTORE -lKINFITTER -lTAC \ + -L$(SQLITECPP_HOME)/lib -lSQLiteCpp -L$(SQLITE_HOME)/lib -Wl,-rpath=$(SQLITE_HOME)/lib -lsqlite3 \ -lxstream -lbz2 -lz \ -L/usr/lib64/mysql -lmysqlclient\ -L$(JANA_HOME)/lib -lJANA \ @@ -83,31 +90,50 @@ INTYLIBS += -Wl,--whole-archive $(DANALIBS) -Wl,--no-whole-archive INTYLIBS += -fPIC -I$(HDDS_HOME) -I$(XERCESCROOT)/include INTYLIBS += -L${XERCESCROOT}/lib -lxerces-c INTYLIBS += -L$(G4TMPDIR) -lhdds -INTYLIBS += -lboost_python $(shell python-config --ldflags) +INTYLIBS += -lboost_python -L$(shell python-config --prefix)/lib $(shell python-config --ldflags) INTYLIBS += -L$(G4ROOT)/lib64 $(patsubst $(G4ROOT)/lib64/lib%.so, -l%, $(G4shared_libs)) +INTYLIBS += -lgfortran +INTYLIBS += -L/usr/lib64 + +EXTRALIBS += -lG4fixes .PHONY: all -all: hdds cobrems sharedlib exe lib bin g4py +all: hdds cobrems G4fixes_symlink g4fixes sharedlib exe lib bin g4py include $(G4INSTALL)/config/binmake.gmk cobrems: $(G4TMPDIR)/libcobrems.so hdds: $(G4TMPDIR)/libhdds.so +g4fixes: $(G4TMPDIR)/libG4fixes.so CXXFLAGS = -O4 -fPIC -W -Wall -pedantic -Wno-non-virtual-dtor -Wno-long-long -$(G4TMPDIR)/libcobrems.so: src/CobremsGeneration.cc +HDDSDIR := $(G4TMPDIR)/hdds +G4FIXESDIR := $(G4TMPDIR)/G4fixes +G4fixes_symlink: + @if [ ! -L src/G4fixes ]; then\ + echo "ERROR - symbolic link G4fixes does not exist in directory src,"\ + "cannot continue!";\ + false;\ + fi + +$(G4TMPDIR)/libcobrems.so: $(Cobrems_sources) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -Wl,--export-dynamic -Wl,-soname,libcobrems.so \ -shared -o $@ $^ $(G4shared_libs) -lboost_python hdgeant4_objects := $(patsubst src/%.cc, $(G4TMPDIR)/%.o, $(hdgeant4_sources)) -G4fixes_objects := $(patsubst src/G4fixes/%.cc, $(G4TMPDIR)/%.o, $(G4fixes_sources)) -G4debug_objects := $(patsubst src/G4debug/%.cc, $(G4TMPDIR)/%.o, $(G4debug_sources)) +G4fixes_objects := $(patsubst src/G4fixes/%.cc, $(G4FIXESDIR)/%.o, $(G4fixes_sources)) +G4debug_objects := $(patsubst src/G4debug/%.cc, $(G4FIXESDIR)/%.o, $(G4debug_sources)) sharedlib: $(G4TMPDIR)/libhdgeant4.so -$(G4TMPDIR)/libhdgeant4.so: $(hdgeant4_objects) $(G4fixes_objects) $(G4debug_objects) +$(G4TMPDIR)/libhdgeant4.so: $(hdgeant4_objects) + +$(G4TMPDIR)/libG4fixes.so: $(G4FIXESDIR)/G4fixes.o $(G4fixes_objects) $(G4debug_objects) + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -Wl,--export-dynamic -Wl,-soname,libG4fixes.so \ + -shared -o $@ $^ $(G4shared_libs) -lboost_python -$(G4TMPDIR)/%.o: src/G4fixes/%.cc +$(G4FIXESDIR)/G4fixes.o: src/G4fixes.cc + @mkdir -p $(G4FIXESDIR) ifdef CPPVERBOSE $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $^ else @@ -115,7 +141,17 @@ else @$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $^ endif -$(G4TMPDIR)/%.o: src/G4debug/%.cc +$(G4fixes_objects): $(G4FIXESDIR)/%.o: src/G4fixes/%.cc + @mkdir -p $(G4FIXESDIR) +ifdef CPPVERBOSE + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $^ +else + @echo Compiling $*.cc ... + @$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $^ +endif + +$(G4debug_objects): $(G4FIXESDIR)/%.o: src/G4debug/%.cc + @mkdir -p $(G4FIXESDIR) ifdef CPPVERBOSE $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $^ else @@ -123,7 +159,6 @@ else @$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $^ endif -HDDSDIR := $(G4TMPDIR)/hdds $(HDDSDIR)/%.o: $(HDDS_HOME)/%.cpp @mkdir -p $(HDDSDIR) ifdef CPPVERBOSE @@ -140,7 +175,8 @@ exe: @mkdir -p $(G4LIBDIR)/$@ g4py: $(G4LIBDIR)/../../../g4py/HDGeant4/libhdgeant4.so \ - $(G4LIBDIR)/../../../g4py/Cobrems/libcobrems.so + $(G4LIBDIR)/../../../g4py/Cobrems/libcobrems.so \ + $(G4LIBDIR)/../../../g4py/G4fixes/libG4fixes.so $(G4LIBDIR)/../../../g4py/HDGeant4/libhdgeant4.so: $(G4LIBDIR)/libhdgeant4.so @rm -f $@ @@ -150,7 +186,14 @@ $(G4LIBDIR)/../../../g4py/Cobrems/libcobrems.so: $(G4LIBDIR)/libcobrems.so @rm -f $@ @cd g4py/Cobrems && ln -s ../../tmp/*/hdgeant4/libcobrems.so . -utils: $(G4BINDIR)/beamtree +$(G4LIBDIR)/../../../g4py/G4fixes/libG4fixes.so: $(G4LIBDIR)/libG4fixes.so + @rm -f $@ + @cd g4py/G4fixes && ln -s ../../tmp/*/hdgeant4/libG4fixes.so . + +utils: $(G4BINDIR)/beamtree $(G4BINDIR)/genBH $(G4BINDIR)/beamtree: src/utils/beamtree.cc $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $^ -L$(G4LIBDIR) -lhdgeant4 $(ROOTLIBS) -Wl,-rpath=$(G4LIBDIR) + +$(G4BINDIR)/genBH: src/utils/genBH.cc + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $^ -L$(G4LIBDIR) -lhdgeant4 $(DANALIBS) $(ROOTLIBS) -Wl,-rpath=$(G4LIBDIR) diff --git a/GNUmakefile.OSX b/GNUmakefile.OSX index 1e4e868..5bca562 100644 --- a/GNUmakefile.OSX +++ b/GNUmakefile.OSX @@ -23,7 +23,7 @@ endif CPPFLAGS += -I$(HDDS_HOME) -I./src -I./src/G4fixes CPPFLAGS += -I./src/G4debug -CPPFLAGS += -I$(HALLD_HOME)/$(BMS_OSNAME)/include +CPPFLAGS += -I$(HALLD_RECON_HOME)/$(BMS_OSNAME)/include CPPFLAGS += -I$(JANA_HOME)/include CPPFLAGS += -I$(shell root-config --incdir) CPPFLAGS += -I/usr/include/Qt @@ -46,6 +46,9 @@ CPPFLAGS += -DG4MULTITHREADED #CPPFLAGS += -DDEBUG_SECTIONPLANE #CPPFLAGS += -DDEBUG_SECTIONPLANE_ZAVE +# If you want to build against Geant4.10.03 or greater, you will need this line uncommented +CPPFLAGS += -DG4VUSERPHYSICSLIST_HAS_GETPARTICLEITERATOR + G4LIB_USE_GDML = 1 CPPVERBOSE = 1 #G4DEBUG = 1 @@ -57,11 +60,12 @@ HDDS_sources := $(HDDS_HOME)/XString.cpp $(HDDS_HOME)/XParsers.cpp $(HDDS_HOME)/ ROOTLIBS = $(shell root-config --libs) -lGeom -lTMVA -lTreePlayer -DANALIBS = -L$(HALLD_HOME)/$(BMS_OSNAME)/lib -lHDGEOMETRY -lDANA \ +DANALIBS = -L$(HALLD_RECON_HOME)/$(BMS_OSNAME)/lib -lHDGEOMETRY -lDANA \ -lANALYSIS -lBCAL -lCCAL -lCDC -lCERE -lDIRC -lFCAL \ -lFDC -lFMWPC -lHDDM -lPAIR_SPECTROMETER -lPID -lRF \ -lSTART_COUNTER -lTAGGER -lTOF -lTPOL -lTRACKING \ - -lTRIGGER -lDAQ -lTTAB -lEVENTSTORE -lKINFITTER \ + -lTRIGGER -lDAQ -lTTAB -lEVENTSTORE -lKINFITTER -lTAC \ + -L$(SQLITECPP_HOME)/lib -lSQLiteCpp -lsqlite3 \ -lxstream -lbz2 -lz \ $(shell mysql_config --libs) \ -L$(JANA_HOME)/lib -lJANA \ @@ -70,26 +74,27 @@ DANALIBS = -L$(HALLD_HOME)/$(BMS_OSNAME)/lib -lHDGEOMETRY -lDANA \ $(ROOTLIBS) \ -lpthread -ldl -G4shared_libs := $(wildcard $(G4ROOT)/lib64/*.so) +G4shared_libs := $(wildcard $(G4ROOT)/lib/*.dylib) INTYLIBS += $(DANALIBS) INTYLIBS += -fPIC -I$(HDDS_HOME) -I$(XERCESCROOT)/include INTYLIBS += -L${XERCESCROOT}/lib -lxerces-c INTYLIBS += -L$(G4TMPDIR) -lhdds INTYLIBS += -lboost_python $(shell python-config --libs) -INTYLIBS += -L$(G4ROOT)/lib64 $(patsubst $(G4ROOT)/lib64/lib%.so, -l%, $(G4shared_libs)) +INTYLIBS += -L$(G4ROOT)/lib $(patsubst $(G4ROOT)/lib/lib%.dylib, -l%, $(G4shared_libs)) +INTYLIBS += -lgfortran .PHONY: all all: hdds cobrems sharedlib exe lib bin g4py include $(G4INSTALL)/config/binmake.gmk -cobrems: $(G4TMPDIR)/libcobrems.so -hdds: $(G4TMPDIR)/libhdds.so +cobrems: $(G4TMPDIR)/libcobrems.dylib +hdds: $(G4TMPDIR)/libhdds.dylib CXXFLAGS = -O3 -fPIC -W -Wall -pedantic -Wno-non-virtual-dtor -Wno-long-long -$(G4TMPDIR)/libcobrems.so: src/CobremsGeneration.cc +$(G4TMPDIR)/libcobrems.dylib: src/CobremsGeneration.cc $(CXX) $(CXXFLAGS) $(CPPFLAGS) \ -flat_namespace -undefined suppress \ -shared -o $@ $^ $(G4shared_libs) -lboost_python @@ -97,9 +102,9 @@ $(G4TMPDIR)/libcobrems.so: src/CobremsGeneration.cc hdgeant4_objects := $(patsubst src/%.cc, $(G4TMPDIR)/%.o, $(hdgeant4_sources)) G4fixes_objects := $(patsubst src/G4fixes/%.cc, $(G4TMPDIR)/%.o, $(G4fixes_sources)) G4debug_objects := $(patsubst src/G4debug/%.cc, $(G4TMPDIR)/%.o, $(G4debug_sources)) -sharedlib: $(G4TMPDIR)/libhdgeant4.so +sharedlib: $(G4TMPDIR)/libhdgeant4.dylib -$(G4TMPDIR)/libhdgeant4.so: $(hdgeant4_objects) $(G4fixes_objects) $(G4debug_objects) +$(G4TMPDIR)/libhdgeant4.dylib: $(hdgeant4_objects) $(G4fixes_objects) $(G4debug_objects) $(G4TMPDIR)/%.o: src/G4fixes/%.cc ifdef CPPVERBOSE @@ -127,22 +132,22 @@ else @$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $^ endif -$(G4TMPDIR)/libhdds.so: $(patsubst $(HDDS_HOME)/%.cpp, $(HDDSDIR)/%.o, $(HDDS_sources)) +$(G4TMPDIR)/libhdds.dylib: $(patsubst $(HDDS_HOME)/%.cpp, $(HDDSDIR)/%.o, $(HDDS_sources)) @$(CXX) -flat_namespace -undefined suppress -shared -o $@ $^ exe: @mkdir -p $(G4LIBDIR)/$@ -g4py: $(G4LIBDIR)/../../../g4py/HDGeant4/libhdgeant4.so \ - $(G4LIBDIR)/../../../g4py/Cobrems/libcobrems.so +g4py: $(G4LIBDIR)/../../../g4py/HDGeant4/libhdgeant4.dylib \ + $(G4LIBDIR)/../../../g4py/Cobrems/libcobrems.dylib -$(G4LIBDIR)/../../../g4py/HDGeant4/libhdgeant4.so: $(G4LIBDIR)/libhdgeant4.so +$(G4LIBDIR)/../../../g4py/HDGeant4/libhdgeant4.dylib: $(G4LIBDIR)/libhdgeant4.dylib @rm -f $@ - @cd g4py/HDGeant4 && ln -s ../../tmp/*/hdgeant4/libhdgeant4.so . + @cd g4py/HDGeant4 && ln -s ../../tmp/*/hdgeant4/libhdgeant4.dylib . -$(G4LIBDIR)/../../../g4py/Cobrems/libcobrems.so: $(G4LIBDIR)/libcobrems.so +$(G4LIBDIR)/../../../g4py/Cobrems/libcobrems.dylib: $(G4LIBDIR)/libcobrems.dylib @rm -f $@ - @cd g4py/Cobrems && ln -s ../../tmp/*/hdgeant4/libcobrems.so . + @cd g4py/Cobrems && ln -s ../../tmp/*/hdgeant4/libcobrems.dylib . utils: $(G4BINDIR)/beamtree diff --git a/g4py/G4fixes/__init__.py b/g4py/G4fixes/__init__.py new file mode 100644 index 0000000..6a287c1 --- /dev/null +++ b/g4py/G4fixes/__init__.py @@ -0,0 +1,3 @@ +# G4fixes python module + +from libG4fixes import * diff --git a/g4py/cobrems.py b/g4py/cobrems.py index 724f82d..7952d5c 100644 --- a/g4py/cobrems.py +++ b/g4py/cobrems.py @@ -25,6 +25,7 @@ E0 = 12 Erms = 0.0006 emit = 2.5e-9 +spot = 0.5e-3 dist = 76 coldiam = 0.0034 radt = 20e-6 @@ -39,12 +40,12 @@ eElim1 = 11.7 # initialize the built-in generator to defaults -generator = CobremsGenerator(E0, Epeak) +generator = CobremsGeneration(E0, Epeak) def usage(): """ Print a brief summary of the internal configuration variables - that regulate the behavior of the CobremsGenerator and exit. + that regulate the behavior of the CobremsGeneration and exit. """ print """ Usage: cobrems.init(key=value, ...) @@ -54,6 +55,7 @@ def usage(): * E0 - mean energy (GeV) of electron beam [12] * Erms - rms energy width (GeV) of electron beam [0.0006] * emit - transverse emittance (m rad) of electron beam [2.5e-9] + * spot - virtual e-beam spot rms (m) at primary collimator [0.5e-3] * dist - distance (m) from radiator to primary collimator [76] * coldiam - diameter (m) of primary collimator [0.0034] * radt - thickness (m) of radiator crystal [20e-6] @@ -95,6 +97,10 @@ def init(**kwargs): global emit emit = value generator.setBeamEmittance(emit) + elif arg == "spot": + global spot + spot = value + generator.setCollimatorSpotrms(spot) elif arg == "dist": global dist dist = value @@ -214,7 +220,10 @@ def plotCoherent(collimated=1): # convert the result to a spectrum vs photon energy global dRcdkH1 dRcdkH1 = 0 - title = "collimated photon beam spectrum, coherent part only" + if collimated: + title = "collimated photon beam spectrum, coherent part only" + else: + title = "uncollimated photon beam spectrum, coherent part only" dRcdkH1 = TH1D("dRcdkH1", title, nbins, Emin, Emax) for i in range(0, nbins): dRcdkH1.Fill(xvals[i] * E0, yvals[i] / E0) @@ -225,6 +234,44 @@ def plotCoherent(collimated=1): dRcdkH1.Draw("hist") return dRcdkH1 +def plotEnhancement(collimated=1): + """ + Plot the ratio of the total diamond spectrum to an amorphous + bremsstrahlung spectrum with the same endpoint, either pre-collimator + (collimated=0) or post-collimator (collimated=1) as a TH1D object. + """ + + # apply the beam-crystal convolution + x0 = Emin / E0 + x1 = Emax / E0 + xvals = array('d', nbins * [0]) + yvals = array('d', nbins * [0]) + colFlag = generator.getCollimatedFlag() + generator.setCollimatedFlag(collimated) + generator.setPolarizedFlag(False) + for i in range(0, nbins): + xvals[i] = x0 + (i + 0.5) * (x1 - x0) / nbins; + yvals[i] = dRcdx([xvals[i]]) / dRidx([xvals[i]]) + 1 + generator.setCollimatedFlag(colFlag) + generator.applyBeamCrystalConvolution(nbins, xvals, yvals) + + # convert the result to a spectrum vs photon energy + global enhanH1 + enhanH1 = 0 + if collimated: + title = "collimated photon beam spectrum, enhancement" + else: + title = "uncollimated photon beam spectrum, enhancement" + enhanH1 = TH1D("enhanH1", title, nbins, Emin, Emax) + for i in range(0, nbins): + enhanH1.Fill(xvals[i] * E0, yvals[i]) + enhanH1.GetXaxis().SetTitle("E_{#gamma} (GeV)") + enhanH1.GetYaxis().SetTitle("enhancement") + enhanH1.GetYaxis().SetTitleOffset(1.5) + enhanH1.SetStats(0) + enhanH1.Draw("hist") + return enhanH1 + def plotIncoherent(collimated=1): """ Plot the incoherent part of the spectrum, either pre-collimator @@ -248,7 +295,10 @@ def plotIncoherent(collimated=1): # convert the result to a spectrum vs photon energy global dRidkH1 dRidkH1 = 0 - title = "collimated photon beam spectrum, incoherent part only" + if collimated: + title = "collimated photon beam spectrum, incoherent part only" + else: + title = "uncollimated photon beam spectrum, incoherent part only" dRidkH1 = TH1D("dRidkH1", title, nbins, Emin, Emax) dRidkH1.GetXaxis().SetRangeUser(Emin + (Emax - Emin)/10., Emax) for i in range(0, nbins): @@ -283,7 +333,10 @@ def plotTotal(collimated=1): # convert the result to a spectrum vs photon energy global dRtdkH1 dRtdkH1 = 0 - title = "collimated photon beam spectrum" + if collimated: + title = "collimated photon beam spectrum" + else: + title = "uncollimated photon beam spectrum" dRtdkH1 = TH1D("dRtdkH1", title, nbins, Emin, Emax) dRtdkH1.GetXaxis().SetRangeUser(Emin + (Emax - Emin)/10., Emax) for i in range(0, nbins): @@ -322,7 +375,10 @@ def plotPolarization(collimated=1): # convert the result to a spectrum vs photon energy global polarH1 polarH1 = 0 - title = "collimated photon beam polarization" + if collimated: + title = "collimated photon beam polarization" + else: + title = "uncollimated photon beam polarization" polarH1 = TH1D("polarH1", title, nbins, Emin, Emax) for i in range(0, nbins): polarH1.Fill(xvals[i] * E0, ypols[i] / yvals[i]) @@ -449,3 +505,74 @@ def plotPolarization_rc(rchist, collimated=1): polarRC.SetStats(0) polarRC.Draw("hist") return polarRC + +# Below are a few functions that are useful in evaluating the +# suppression of the low-energy bremsstrahlung tail due to the +# LPM effect -- see RevModPhys.17.1501 and RevPhys.103.1811. + +hbarc = 0.197e-15 # GeV.m +me = 511e-6 # electron mass, GeV/c^2 +Es = 21.2e-3 # multiple-scattering screening parameter, GeV +X0 = 0.120 # m, radiation length of diamond + +import math +alphaQED = 1 / 137. +X0=6e-3 +E0=25 +E_LPM = me**2 * X0 * alphaQED / (4 * math.pi * hbarc) +k_LPM = E0**2 /E_LPM + +def LPMfl0(k): + """ + Return the free space formation length of bremsstrahlung at + energy k. Units are meters. + """ + return 2 * hbarc * E0 * (E0 - k) / (k * me**2) + +def LPMfl(k): + """ + Return the in-medium formation length of bremsstrahlung at + energy k. Units are meters. + """ + A = Es**2 / (2 * me**2 * X0) + B = 1 + C = -LPMfl0(k) + return (-B + (B**2 - 4 * A * C)**0.5) / (2 * A) + +def LPMStrong(k): + """ + Return the in-medium formation length of bremsstrahlung at + energy k. Units are meters. + """ + return (k * E_LPM / (E0 * (E0 - k)))**0.5 + +def plot_LPMfl(Emax): + """ + Make a plot of the formation lengths vs photon energy. + """ + h0 = TH1D("h0", "bremsstrahlung formation lengths vs k", + 100, 0, Emax * 1e3) + h0.SetStats(0) + h0.SetLineColor(1) + h0.SetLineWidth(2) + h0.GetXaxis().SetTitle("photon energy (MeV)") + h0.GetYaxis().SetTitle("formation lengths (m)") + h0.GetYaxis().SetTitleOffset(1.5) + h1 = h0.Clone("h1") + h2 = h0.Clone("h2") + h2.SetTitle("LPM suppression S(E) in continuous medium (semiclassical)") + h2.GetYaxis().SetTitle("S factor") + h3 = h2.Clone("h3") + for i in range(1, h0.GetNbinsX() + 1): + E = h0.GetXaxis().GetBinCenter(i) * 1e-3 + h0.SetBinContent(i, LPMfl0(E)) + h1.SetBinContent(i, LPMfl(E)) + h2.SetBinContent(i, LPMfl(E) / LPMfl0(E)) + h3.SetBinContent(i, LPMStrong(E)) + h0.Draw('c') + h1.SetLineColor(2) + h2.SetLineColor(6) + h3.SetLineColor(4) + h1.Draw('c same') + return h0,h1,h2,h3 + diff --git a/g4py/hdgeant4.py b/g4py/hdgeant4.py index 1408f3a..eb32aa9 100644 --- a/g4py/hdgeant4.py +++ b/g4py/hdgeant4.py @@ -71,7 +71,7 @@ def init(): global runact global eventact global stepact - runact = GlueXRunAction() + runact = GlueXRunAction(plist) eventact = GlueXEventAction() stepact = GlueXSteppingAction() gRunManager.SetUserAction(runact) diff --git a/macro/dirc/control.in b/macro/dirc/control.in index da3b8ee..17c2ac7 100644 --- a/macro/dirc/control.in +++ b/macro/dirc/control.in @@ -112,13 +112,15 @@ c PLOG 1 c TLOG 1 c c particle momentum theta phi delta_momentum delta_theta delta_phi -KINE 114 4.0 5. -90. 0. 0. 0. +cKINE 1050 0.000000003 90. 0. 0. 0. 0. +KINE 114 4. 5. -90. 0. 0. 0. c The SCAP card determines the vertex position for the particle gun. It c supports the following three arguments, all of which default to 0. c c vertex_x vertex_y vertex_z -SCAP 0. 0. 65. +cSCAP 0. -44.4 595.5 +SCAP 0. 0. 65. c The TGTWIDTH card is used to determine an extended volume from c which the particle gun will generate vertexes. The vertex position @@ -131,7 +133,7 @@ c by SCAP. Note that this only affects the particle gun. Events read c from a file contain their own vertex information. c c vertex_extent_r vertex_extent_z -TGTWIDTH 0.5 15 +TGTWIDTH 0.0 0. c If you specify a non-zero value for vertex_x and/or vertex_y above then c all tracks will emerge from the given point. If you leave them at zero, @@ -245,7 +247,7 @@ c - tofmax = Time of flight cut (1.E+10 sec) c - gcuts = 5 user words (0.) c Only the first 5 fields (the ones that start with 'cut') c are supported by hdgeant4. -CUTS 1e-4 1e-4 1e-3 1e-3 1e-4 +cCUTS 1e-4 1e-4 1e-3 1e-3 1e-4 c Geant4 introduced the concept of ?a unique cut in range? which allows the user c to specify the threshold for secondaries production in terms of the range that diff --git a/macro/dirc/drawHP.C b/macro/dirc/drawHP.C index d314c40..e0afb67 100644 --- a/macro/dirc/drawHP.C +++ b/macro/dirc/drawHP.C @@ -1,5 +1,5 @@ #define glx__sim -#include "../../../sim-recon/src/plugins/Analysis/pid_dirc/DrcEvent.h" +#include "../../../../sim-recon/master/src/plugins/Analysis/pid_dirc/DrcEvent.h" #include "glxtools.C" void drawHP(TString infile="drc.root"){ @@ -21,4 +21,6 @@ void drawHP(TString infile="drc.root"){ glx_drawDigi("m,p,v\n",0); glx_canvasAdd(glx_cdigi); // glx_canvasSave(1,0); + + } diff --git a/macro/dirc/loadlib.C b/macro/dirc/loadlib.C index 6781742..ab7f13b 100644 --- a/macro/dirc/loadlib.C +++ b/macro/dirc/loadlib.C @@ -1,3 +1,4 @@ { - gSystem->Load("../../../sim-recon/Linux_Linux-x86_64-gcc4.9.2/plugins/pid_dirc.so"); + // gSystem->Load("../../../../sim-recon/master/Linux_Linux-x86_64-gcc4.9.2/plugins/pid_dirc.so"); + gSystem->Load("../../../../sim-recon/master/Linux_Ubuntu16.04-x86_64-gcc5.4.0/plugins/pid_dirc.so"); } diff --git a/macro/dirc/vis.mac b/macro/dirc/vis.mac index fd1342c..42d7262 100644 --- a/macro/dirc/vis.mac +++ b/macro/dirc/vis.mac @@ -27,9 +27,9 @@ /vis/scene/create #/vis/scene/add/volume SHLD ! 2 -/vis/scene/add/volume LASS ! 1 +#/vis/scene/add/volume LASS ! 1 /vis/scene/add/volume DCMV -/vis/scene/add/volume FCAL ! 2 +#/vis/scene/add/volume FCAL ! 2 #/vis/scene/add/volume MAG3 ! 2 /vis/sceneHandler/attach diff --git a/src/CobremsGeneration.cc b/src/CobremsGeneration.cc index f667a2b..9288d1a 100644 --- a/src/CobremsGeneration.cc +++ b/src/CobremsGeneration.cc @@ -85,8 +85,11 @@ CobremsGeneration::CobremsGeneration(double Emax_GeV, double Epeak_GeV) #if COBREMS_GENERATOR_VERBOSITY > 0 std::cout << std::endl << "Initialization for coherent bremsstralung calculation" + << std::endl + << " electron beam energy: " << Emax_GeV << " GeV" + << std::endl + << " primary coherent edge: " << Epeak_GeV << " GeV" << std::endl; - printBeamlineInfo(); #endif } @@ -95,9 +98,9 @@ void CobremsGeneration::updateTargetOrientation() resetTargetOrientation(); RotateTarget(0, dpi/2, 0); // point (1,0,0) along beam RotateTarget(0, 0, dpi/4); // point (0,1,1) vertically - RotateTarget(-fTargetThetax, 0, 0); - RotateTarget(0, -fTargetThetay, 0); RotateTarget(0, 0, -fTargetThetaz); + RotateTarget(0, -fTargetThetay, 0); + RotateTarget(-fTargetThetax, 0, 0); } void CobremsGeneration::setTargetCrystal(std::string crystal) @@ -109,7 +112,7 @@ void CobremsGeneration::setTargetCrystal(std::string crystal) fTargetCrystal.Z = 6; fTargetCrystal.A = 12.01; fTargetCrystal.density = 3.534; // g/cm^3 - fTargetCrystal.lattice_constant = 3.56e-10; // m + fTargetCrystal.lattice_constant = 3.5668e-10; // m fTargetCrystal.Debye_Waller_const = 0.40e9; // 1/GeV^2 } else if (crystal == "silicon") { @@ -307,23 +310,14 @@ void CobremsGeneration::applyBeamCrystalConvolution(int nbins, double *xvalues, pow(fBeamEmittance / fCollimatorSpotrms, 2); double varMS = Sigma2MS(fTargetThickness); - // Here we have to guess which characteristic angle alph inside the crystal - // is dominantly responsible for the coherent photons in each bin in x. - // I just use the smallest of the two angles, but this does not work when - // both angles are small, and you have to be more clever -- BEWARE!!! - double alph = (fabs(fTargetThetax) < fabs(fTargetThetay))? - fabs(fTargetThetax) : fabs(fTargetThetay); - if (alph == 0) { - alph = (fabs(fTargetThetax) > fabs(fTargetThetay))? - fabs(fTargetThetax) : fabs(fTargetThetay); - } - - // In any case, fine-tuning below the mosaic spread limit makes no sense. - else { - alph = (alph > fTargetCrystal.mosaic_spread)? - alph : fTargetCrystal.mosaic_spread; - } - + // Here we have to guess which reciprocal lattice vector is dominantly + // for the coherent photons in each bin in x. For simplicity, I assume + // it is a (2,2,0) vector. Higher order vectors exhibit more smearing + // but this is a good approximation if the primary peaks in the spectrum + // come from (2,2,0) vectors. + double a = fTargetCrystal.lattice_constant; + double qabs = sqrt(8.0) * hbarc * 2*dpi / a; + double xfact = 2 * fBeamEnergy * qabs / (me*me); double *norm = new double[nbins]; double *result = new double[nbins]; for (int j=0; j < nbins; ++j) { @@ -332,7 +326,7 @@ void CobremsGeneration::applyBeamCrystalConvolution(int nbins, double *xvalues, for (int i=0; i < nbins; ++i) { double dx = (x1 - x0) * (j - i) / nbins; double x = x0 + (x1 - x0) * (j + 0.5) / nbins; - double dalph = dx * alph / (x * (1 - x) + 1e-99); + double dalph = dx / xfact / pow(1 - x + 1e-99, 2); double term; if (varMS / var0 > 1e-4) { term = dalph / varMS * @@ -346,7 +340,6 @@ void CobremsGeneration::applyBeamCrystalConvolution(int nbins, double *xvalues, else { term = exp(-dalph*dalph / (2 * var0)) / sqrt(2 * dpi * var0); } - term *= alph / x; norm[j] += term; } } @@ -355,7 +348,7 @@ void CobremsGeneration::applyBeamCrystalConvolution(int nbins, double *xvalues, for (int j=0; j < nbins; ++j) { double dx = (x1 - x0) * (j - i) / nbins; double x = x0 + (x1 - x0) * (j + 0.5) / nbins; - double dalph = dx * alph / (x * (1 - x) + 1e-99); + double dalph = dx / xfact / pow(1 - x + 1e-99, 2); double term; if (varMS / var0 > 1e-4) { term = dalph / varMS * @@ -369,7 +362,6 @@ void CobremsGeneration::applyBeamCrystalConvolution(int nbins, double *xvalues, else { term = exp(-dalph*dalph / (2 * var0)) / sqrt(2 * dpi * var0); } - term *= alph / x; result[i] += term * yvalues[j] / norm[j]; } } @@ -530,7 +522,14 @@ double CobremsGeneration::Rate_dNcdx(double x) // Returns the coherent bremsstrahlung probability density differential // in x (scaled photon energy) at photon energy k = x*fBeamEnergy. - return 2 * dpi * Rate_dNcdxdp(x, dpi/4); + double rate = 0; + int npoints = 2; + for (int n=0; n < npoints; ++n) { + double phi = (n + 0.5) * (dpi/2) / npoints; + rate += Rate_dNcdxdp(x, phi); + } + rate *= 2*dpi / npoints; + return rate; } double CobremsGeneration::Rate_dNcdx(double x, @@ -548,7 +547,13 @@ double CobremsGeneration::Rate_dNcdx(double x, fCollimatorDiameter = (diameter_m > 0)? diameter_m : (diameter_m < 0)? -2 * distance_m * diameter_m * me / fBeamEnergy : fCollimatorDiameter; - double rate = 2 * dpi * Rate_dNcdxdp(x, dpi/4); + double rate = 0; + int npoints = 2; + for (int n=0; n < npoints; ++n) { + double phi = (n + 0.5) * (dpi/2) / npoints; + rate += Rate_dNcdxdp(x, phi); + } + rate *= 2*dpi / npoints; fCollimatorDistance = dist; fCollimatorDiameter = diam; return rate; @@ -642,7 +647,7 @@ double CobremsGeneration::Rate_dNcdxdp(double x, double phi) ((1 + pow(1 - x, 2)) - 8 * (theta2 / pow(1 + theta2, 2) * (1 - x) * pow(cos(phi), 2))) * ((fCollimatedFlag)? Acceptance(theta2) : 1) * - ((fPolarizedFlag)? Polarization(x, theta2) : 1); + ((fPolarizedFlag)? Polarization(x, theta2, phi) : 1); fQ2theta2.push_back(theta2); fQ2weight.push_back(sum); } @@ -767,7 +772,7 @@ double CobremsGeneration::Rate_para(double x, double theta2, double phi) return 0.5 * pow((2 - x) * (1 + theta2), 2) - 8 * theta2 * (1 - x) * pow(cos(phi), 2) - - 8 * pow(theta2, 2) * (1 - x) * pow(cos(phi), 2) * pow(sin(phi), 2); + 8 * pow(theta2, 2) * (1 - x) * pow(cos(phi) * sin(phi), 2); } double CobremsGeneration::Rate_ortho(double x, double theta2, double phi) @@ -779,7 +784,7 @@ double CobremsGeneration::Rate_ortho(double x, double theta2, double phi) // expressed in units of (me/fBeamEnergy)^2. return 0.5 * pow(x * (1 + theta2), 2) + - 8 * pow(theta2, 2) * (1 - x) * pow(cos(phi), 2) * pow(sin(phi), 2); + 8 * pow(theta2, 2) * (1 - x) * pow(cos(phi) * sin(phi), 2); } double CobremsGeneration::Polarization(double x, double theta2) @@ -795,6 +800,42 @@ double CobremsGeneration::Polarization(double x, double theta2) 4 * theta2 * (1 - x)); } +double CobremsGeneration::Polarization(double x, double theta2, double phi) +{ + // Returns the degree of linear polarization in a coherent bremsstrahlung + // beam at photon energy k = x*fBeamEnergy and production angles theta, phi. + // The argument theta2 is the production polar angle theta^2 expressed + // in units of (me/fBeamEnergy)^2. + + double Rpara = Rate_para(x, theta2, phi); + double Rperp = Rate_ortho(x, theta2, phi); + return (Rpara - Rperp) / (Rpara + Rperp); +} + +double CobremsGeneration::AbremsPolarization(double x, double theta2, double phi) +{ + // Returns the degree of linear polarization in an ordinary atomic + // bremsstrahlung beam at photon energy k = x*fBeamEnergy and production + // angles theta,phi. The formula is a parameterization of the linear + // polarization evaluated using the Dirac++ QED Monte Carlo generator. + // The argument theta2 is the production polar angle theta^2 expressed + // in units of (me/fBeamEnergy)^2. + + double Acoeff[3][4] = {{0.93000, 0.64250, 0.66598, 1.62506}, + {0.73000, 1.05648, 0.84643, 1.97061}, + {0.87610, 0.57510, 0.74918, 1.52849}}; + double a[3]; + for (int n=0; n < 3; ++n) { + double A = pow(Acoeff[n][0], 2) + + pow(Acoeff[n][1], 2) * pow(x, 2) + + pow(Acoeff[n][2], 2) * pow(x, 4) + + pow(Acoeff[n][3], 2) * pow(x, 16); + a[n] = A*A; + } + double ppol = theta2 / (a[0] + a[1] * theta2 + a[2] * theta2*theta2); + return ppol * cos(2 * phi); +} + double CobremsGeneration::Acceptance(double theta2, double phi, double xshift_m, double yshift_m) { @@ -1048,6 +1089,8 @@ double (CobremsGeneration::*Rate_dNcdx_1)(double) = &CobremsGeneration::Rate_dNc double (CobremsGeneration::*Rate_dNcdx_3)(double, double, double) = &CobremsGeneration::Rate_dNcdx; double (CobremsGeneration::*Acceptance_1)(double) = &CobremsGeneration::Acceptance; double (CobremsGeneration::*Acceptance_4)(double, double, double, double) = &CobremsGeneration::Acceptance; +double (CobremsGeneration::*Polarization_2)(double, double) = &CobremsGeneration::Polarization; +double (CobremsGeneration::*Polarization_3)(double, double, double) = &CobremsGeneration::Polarization; BOOST_PYTHON_MODULE(libcobrems) { @@ -1116,7 +1159,8 @@ BOOST_PYTHON_MODULE(libcobrems) .def("Rate_dNidxdt2", &CobremsGeneration::Rate_dNidxdt2) .def("Rate_para", &CobremsGeneration::Rate_para) .def("Rate_ortho", &CobremsGeneration::Rate_ortho) - .def("Polarization", &CobremsGeneration::Polarization) + .def("Polarization", Polarization_2) + .def("Polarization", Polarization_3) .def("Acceptance", Acceptance_1) .def("Acceptance", Acceptance_4) .def("Sigma2MS", &CobremsGeneration::Sigma2MS) diff --git a/src/CobremsGeneration.hh b/src/CobremsGeneration.hh index 881b120..75f101f 100644 --- a/src/CobremsGeneration.hh +++ b/src/CobremsGeneration.hh @@ -148,6 +148,8 @@ class CobremsGeneration { double Rate_para(double x, double theta2, double phi); double Rate_ortho(double x, double theta2, double phi); double Polarization(double x, double theta2); + double Polarization(double x, double theta2, double phi); + double AbremsPolarization(double x, double theta2, double phi); double Acceptance(double theta2, double phi, double xshift_m, double yshift_m); double Acceptance(double theta2); diff --git a/src/G4.10.01.p02fixes/G4IntersectingCone.cc b/src/G4.10.01.p02fixes/G4IntersectingCone.cc index 6848e1d..26143a2 100644 --- a/src/G4.10.01.p02fixes/G4IntersectingCone.cc +++ b/src/G4.10.01.p02fixes/G4IntersectingCone.cc @@ -233,8 +233,8 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, // if (std::fabs(a) > 1/kInfinity) { - if(B==0.) { return 0; } - if ( std::fabs(x0*ty - y0*tx) < std::fabs(1e-6/(B+1e-99)) ) + //if(B==0.) { return 0; } + //if ( std::fabs(x0*ty - y0*tx) < std::fabs(1e-6/(B+1e-99)) ) { *s1 = -0.5*b/a; return 1; @@ -336,7 +336,7 @@ G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, // if (std::fabs(a) > 1/kInfinity) { - if ( std::fabs(x0*ty - y0*tx) < std::fabs(1e-6/(B+1e-99)) ) + //if ( std::fabs(x0*ty - y0*tx) < std::fabs(1e-6/(B+1e-99)) ) { *s1 = -0.5*b/a; return 1; diff --git a/src/G4.10.01.p02fixes/G4ParallelWorldProcess.cc b/src/G4.10.01.p02fixes/G4ParallelWorldProcess.cc new file mode 100644 index 0000000..d6b5654 --- /dev/null +++ b/src/G4.10.01.p02fixes/G4ParallelWorldProcess.cc @@ -0,0 +1,438 @@ +// +// ******************************************************************** +// * 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: G4ParallelWorldProcess.cc 86967 2014-11-21 11:51:28Z gcosmo $ +// GEANT4 tag $Name: geant4-09-04-ref-00 $ +// +// + +#include "G4ios.hh" +#include "G4ParallelWorldProcess.hh" +#include "G4ParallelWorldProcessStore.hh" +#include "G4Step.hh" +#include "G4StepPoint.hh" +#include "G4Navigator.hh" +#include "G4VTouchable.hh" +#include "G4VPhysicalVolume.hh" +#include "G4ParticleChange.hh" +#include "G4PathFinder.hh" +#include "G4TransportationManager.hh" +#include "G4ParticleChange.hh" +#include "G4StepPoint.hh" +#include "G4FieldTrackUpdator.hh" +#include "G4Material.hh" +#include "G4ProductionCuts.hh" +#include "G4ProductionCutsTable.hh" + +#include "G4SDManager.hh" +#include "G4VSensitiveDetector.hh" + +G4ThreadLocal G4Step* G4ParallelWorldProcess::fpHyperStep = 0; +G4ThreadLocal G4int G4ParallelWorldProcess::nParallelWorlds = 0; +G4ThreadLocal G4int G4ParallelWorldProcess::fNavIDHyp = 0; +const G4Step* G4ParallelWorldProcess::GetHyperStep() +{ return fpHyperStep; } +G4int G4ParallelWorldProcess::GetHypNavigatorID() +{ return fNavIDHyp; } + +G4ParallelWorldProcess:: +G4ParallelWorldProcess(const G4String& processName,G4ProcessType theType) +:G4VProcess(processName,theType), fGhostNavigator(0), fNavigatorID(-1), + fFieldTrack('0'),layeredMaterialFlag(false) +{ + if(!fpHyperStep) fpHyperStep = new G4Step(); + iParallelWorld = ++nParallelWorlds; + + pParticleChange = &aDummyParticleChange; + + fGhostStep = new G4Step(); + fGhostPreStepPoint = fGhostStep->GetPreStepPoint(); + fGhostPostStepPoint = fGhostStep->GetPostStepPoint(); + + fTransportationManager = G4TransportationManager::GetTransportationManager(); + fTransportationManager->GetNavigatorForTracking()->SetPushVerbosity(false); + fPathFinder = G4PathFinder::GetInstance(); + + fGhostWorldName = "** NotDefined **"; + fGhostWorld = 0; + fGhostSafety = 0.; + fOnBoundary = false; + + G4ParallelWorldProcessStore::GetInstance()->SetParallelWorld(this,processName); + + if (verboseLevel>0) + { + G4cout << GetProcessName() << " is created " << G4endl; + } +} + +G4ParallelWorldProcess::~G4ParallelWorldProcess() +{ + delete fGhostStep; + nParallelWorlds--; + if(nParallelWorlds==0) + { + delete fpHyperStep; + fpHyperStep = 0; + } +} + +void G4ParallelWorldProcess:: +SetParallelWorld(G4String parallelWorldName) +{ + fGhostWorldName = parallelWorldName; + fGhostWorld = fTransportationManager->GetParallelWorld(fGhostWorldName); + fGhostNavigator = fTransportationManager->GetNavigator(fGhostWorld); + fGhostNavigator->SetPushVerbosity(false); +} + +void G4ParallelWorldProcess:: +SetParallelWorld(G4VPhysicalVolume* parallelWorld) +{ + fGhostWorldName = parallelWorld->GetName(); + fGhostWorld = parallelWorld; + fGhostNavigator = fTransportationManager->GetNavigator(fGhostWorld); + fGhostNavigator->SetPushVerbosity(false); +} + +void G4ParallelWorldProcess::StartTracking(G4Track* trk) +{ + if(fGhostNavigator) + { fNavigatorID = fTransportationManager->ActivateNavigator(fGhostNavigator); } + else + { + G4Exception("G4ParallelWorldProcess::StartTracking", + "ProcParaWorld000",FatalException, + "G4ParallelWorldProcess is used for tracking without having a parallel world assigned"); + } + fPathFinder->PrepareNewTrack(trk->GetPosition(),trk->GetMomentumDirection()); + + fOldGhostTouchable = fPathFinder->CreateTouchableHandle(fNavigatorID); + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fNewGhostTouchable = fOldGhostTouchable; + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + + fGhostSafety = -1.; + fOnBoundary = false; + fGhostPreStepPoint->SetStepStatus(fUndefined); + fGhostPostStepPoint->SetStepStatus(fUndefined); + +// G4VPhysicalVolume* thePhys = fNewGhostTouchable->GetVolume(); +// if(thePhys) +// { +// G4Material* ghostMaterial = thePhys->GetLogicalVolume()->GetMaterial(); +// if(ghostMaterial) +// { G4cout << " --- Material : " << ghostMaterial->GetName() << G4endl; } +// } + + *(fpHyperStep->GetPostStepPoint()) = *(trk->GetStep()->GetPostStepPoint()); + if(layeredMaterialFlag) + { + G4StepPoint* realWorldPostStepPoint = trk->GetStep()->GetPostStepPoint(); + SwitchMaterial(realWorldPostStepPoint); + G4StepPoint *realWorldPreStepPoint = trk->GetStep()->GetPreStepPoint(); + SwitchMaterial(realWorldPreStepPoint); + G4double velocity = trk->CalculateVelocity(); + realWorldPostStepPoint->SetVelocity(velocity); + realWorldPreStepPoint->SetVelocity(velocity); + trk->SetVelocity(velocity); + } + *(fpHyperStep->GetPreStepPoint()) = *(fpHyperStep->GetPostStepPoint()); +} + +G4double +G4ParallelWorldProcess::AtRestGetPhysicalInteractionLength( + const G4Track& /*track*/, + G4ForceCondition* condition) +{ +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// At Rest must be registered ONLY for the particle which has other At Rest +// process(es). +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + *condition = Forced; + return DBL_MAX; +} + +G4VParticleChange* G4ParallelWorldProcess::AtRestDoIt( + const G4Track& track, + const G4Step& step) +{ +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// At Rest must be registered ONLY for the particle which has other At Rest +// process(es). +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fOldGhostTouchable = fGhostPostStepPoint->GetTouchableHandle(); + G4VSensitiveDetector* aSD = 0; + if(fOldGhostTouchable->GetVolume()) + { aSD = fOldGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector(); } + fOnBoundary = false; + if(aSD) + { + CopyStep(step); + fGhostPreStepPoint->SetSensitiveDetector(aSD); + + fNewGhostTouchable = fOldGhostTouchable; + + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + if(fNewGhostTouchable->GetVolume()) + { + fGhostPostStepPoint->SetSensitiveDetector( + fNewGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector()); + } + else + { fGhostPostStepPoint->SetSensitiveDetector(0); } + + aSD->Hit(fGhostStep); + } + + pParticleChange->Initialize(track); + return pParticleChange; +} + +G4double +G4ParallelWorldProcess::PostStepGetPhysicalInteractionLength( + const G4Track& /*track*/, + G4double /*previousStepSize*/, + G4ForceCondition* condition) +{ + *condition = StronglyForced; + return DBL_MAX; +} + +G4VParticleChange* G4ParallelWorldProcess::PostStepDoIt( + const G4Track& track, + const G4Step& step) +{ + fOldGhostTouchable = fGhostPostStepPoint->GetTouchableHandle(); + G4VSensitiveDetector* aSD = 0; + if(fOldGhostTouchable->GetVolume()) + { aSD = fOldGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector(); } + CopyStep(step); + fGhostPreStepPoint->SetSensitiveDetector(aSD); + + if(fOnBoundary) + { + fNewGhostTouchable = fPathFinder->CreateTouchableHandle(fNavigatorID); + } + else + { + fNewGhostTouchable = fOldGhostTouchable; + } + + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + + if(fNewGhostTouchable->GetVolume()) + { + fGhostPostStepPoint->SetSensitiveDetector( + fNewGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector()); + } + else + { fGhostPostStepPoint->SetSensitiveDetector(0); } + + G4VSensitiveDetector* sd = fGhostPreStepPoint->GetSensitiveDetector(); + if(sd) + { + sd->Hit(fGhostStep); + } + + pParticleChange->Initialize(track); + if(layeredMaterialFlag) + { + G4StepPoint* realWorldPostStepPoint = + ((G4Step*)(track.GetStep()))->GetPostStepPoint(); + SwitchMaterial(realWorldPostStepPoint); + } + return pParticleChange; +} + +G4double G4ParallelWorldProcess::AlongStepGetPhysicalInteractionLength( + const G4Track& track, G4double previousStepSize, G4double currentMinimumStep, + G4double& proposedSafety, G4GPILSelection* selection) +{ + static G4ThreadLocal G4FieldTrack *endTrack_G4MT_TLS_ = 0 ; if (!endTrack_G4MT_TLS_) endTrack_G4MT_TLS_ = new G4FieldTrack ('0') ; G4FieldTrack &endTrack = *endTrack_G4MT_TLS_; + //static ELimited eLimited; + ELimited eLimited; + ELimited eLim = kUndefLimited; + + *selection = NotCandidateForSelection; + G4double returnedStep = DBL_MAX; + + if (previousStepSize > 0.) + { fGhostSafety -= previousStepSize; } + if (fGhostSafety < 0.) fGhostSafety = 0.0; + + if (currentMinimumStep <= fGhostSafety && currentMinimumStep > 0.) + { + // I have no chance to limit + returnedStep = currentMinimumStep; + fOnBoundary = false; + proposedSafety = fGhostSafety - currentMinimumStep; + eLim = kDoNot; + } + else + { + G4FieldTrackUpdator::Update(&fFieldTrack,&track); + returnedStep + = fPathFinder->ComputeStep(fFieldTrack,currentMinimumStep,fNavigatorID, + track.GetCurrentStepNumber(),fGhostSafety,eLimited, + endTrack,track.GetVolume()); + if(eLimited == kDoNot) + { + fOnBoundary = false; + fGhostSafety = fGhostNavigator->ComputeSafety(endTrack.GetPosition()); + } + else + { + fOnBoundary = true; + } + proposedSafety = fGhostSafety; + if(eLimited == kUnique || eLimited == kSharedOther) { + *selection = CandidateForSelection; + } + else if (eLimited == kSharedTransport) { + returnedStep *= (1.0 + 1.0e-9); + } + eLim = eLimited; + } + + if(iParallelWorld==nParallelWorlds) fNavIDHyp = 0; + if(eLim == kUnique || eLim == kSharedOther) fNavIDHyp = fNavigatorID; + return returnedStep; +} + +G4VParticleChange* G4ParallelWorldProcess::AlongStepDoIt( + const G4Track& track, const G4Step& ) +{ + pParticleChange->Initialize(track); + return pParticleChange; +} + +void G4ParallelWorldProcess::CopyStep(const G4Step & step) +{ + G4StepStatus prevStat = fGhostPostStepPoint->GetStepStatus(); + + fGhostStep->SetTrack(step.GetTrack()); + fGhostStep->SetStepLength(step.GetStepLength()); + fGhostStep->SetTotalEnergyDeposit(step.GetTotalEnergyDeposit()); + fGhostStep->SetNonIonizingEnergyDeposit(step.GetNonIonizingEnergyDeposit()); + fGhostStep->SetControlFlag(step.GetControlFlag()); + + *fGhostPreStepPoint = *(step.GetPreStepPoint()); + *fGhostPostStepPoint = *(step.GetPostStepPoint()); + + fGhostPreStepPoint->SetStepStatus(prevStat); + if(fOnBoundary) + { fGhostPostStepPoint->SetStepStatus(fGeomBoundary); } + else if(fGhostPostStepPoint->GetStepStatus()==fGeomBoundary) + { fGhostPostStepPoint->SetStepStatus(fPostStepDoItProc); } + + if(iParallelWorld==1) + { + G4StepStatus prevStatHyp = fpHyperStep->GetPostStepPoint()->GetStepStatus(); + + fpHyperStep->SetTrack(step.GetTrack()); + fpHyperStep->SetStepLength(step.GetStepLength()); + fpHyperStep->SetTotalEnergyDeposit(step.GetTotalEnergyDeposit()); + fpHyperStep->SetNonIonizingEnergyDeposit(step.GetNonIonizingEnergyDeposit()); + fpHyperStep->SetControlFlag(step.GetControlFlag()); + + *(fpHyperStep->GetPreStepPoint()) = *(fpHyperStep->GetPostStepPoint()); + *(fpHyperStep->GetPostStepPoint()) = *(step.GetPostStepPoint()); + + fpHyperStep->GetPreStepPoint()->SetStepStatus(prevStatHyp); + } + + if(fOnBoundary) + { fpHyperStep->GetPostStepPoint()->SetStepStatus(fGeomBoundary); } +} + +void G4ParallelWorldProcess::SwitchMaterial(G4StepPoint* realWorldStepPoint) +{ + if(realWorldStepPoint->GetStepStatus()==fWorldBoundary) return; + G4VPhysicalVolume* thePhys = fNewGhostTouchable->GetVolume(); + if(thePhys) + { + G4Material* ghostMaterial = thePhys->GetLogicalVolume()->GetMaterial(); + if(ghostMaterial) + { + G4Region* ghostRegion = thePhys->GetLogicalVolume()->GetRegion(); + G4ProductionCuts* prodCuts = + realWorldStepPoint->GetMaterialCutsCouple()->GetProductionCuts(); + if(ghostRegion) + { + G4ProductionCuts* ghostProdCuts = ghostRegion->GetProductionCuts(); + if(ghostProdCuts) prodCuts = ghostProdCuts; + } + const G4MaterialCutsCouple* ghostMCCouple = + G4ProductionCutsTable::GetProductionCutsTable() + ->GetMaterialCutsCouple(ghostMaterial,prodCuts); + if(ghostMCCouple) + { + realWorldStepPoint->SetMaterial(ghostMaterial); + realWorldStepPoint->SetMaterialCutsCouple(ghostMCCouple); + *(fpHyperStep->GetPostStepPoint()) = *(fGhostPostStepPoint); + fpHyperStep->GetPostStepPoint()->SetMaterial(ghostMaterial); + fpHyperStep->GetPostStepPoint()->SetMaterialCutsCouple(ghostMCCouple); + } + else + { + G4cout << "!!! MaterialCutsCouple is not found for " + << ghostMaterial->GetName() << "." << G4endl + << " Material in real world (" + << realWorldStepPoint->GetMaterial()->GetName() + << ") is used." << G4endl; + } + } + } +} + +G4bool G4ParallelWorldProcess::IsAtRestRequired(G4ParticleDefinition* partDef) +{ + G4int pdgCode = partDef->GetPDGEncoding(); + if(pdgCode==0) + { + G4String partName = partDef->GetParticleName(); + if(partName=="opticalphoton") return false; + if(partName=="geantino") return false; + if(partName=="chargedgeantino") return false; + } + else + { + if(pdgCode==22) return false; // gamma + if(pdgCode==11) return false; // electron + if(pdgCode==2212) return false; // proton + if(pdgCode==-12) return false; // anti_nu_e + if(pdgCode==12) return false; // nu_e + if(pdgCode==-14) return false; // anti_nu_mu + if(pdgCode==14) return false; // nu_mu + if(pdgCode==-16) return false; // anti_nu_tau + if(pdgCode==16) return false; // nu_tau + } + return true; +} + diff --git a/src/G4.10.02.p02fixes/G4CoupledTransportation.cc b/src/G4.10.02.p02fixes/G4CoupledTransportation.cc new file mode 100644 index 0000000..1472b71 --- /dev/null +++ b/src/G4.10.02.p02fixes/G4CoupledTransportation.cc @@ -0,0 +1,1012 @@ +// +// ******************************************************************** +// * 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: G4CoupledTransportation.cc 87829 2015-01-14 17:19:59Z gcosmo $ +// +// ------------------------------------------------------------ +// GEANT 4 class implementation +// ======================================================================= +// Modified: +// 10 Jan 2015, M.Kelsey: Use G4DynamicParticle mass, NOT PDGMass +// 13 May 2006, J. Apostolakis: Revised for parallel navigation (PathFinder) +// 19 Jan 2006, P.MoraDeFreitas: Fix for suspended tracks (StartTracking) +// 11 Aug 2004, M.Asai: Add G4VSensitiveDetector* for updating stepPoint. +// 21 June 2003, J.Apostolakis: Calling field manager with +// track, to enable it to configure its accuracy +// 13 May 2003, J.Apostolakis: Zero field areas now taken into +// account correclty in all cases (thanks to W Pokorski). +// 29 June 2001, J.Apostolakis, D.Cote-Ahern, P.Gumplinger: +// correction for spin tracking +// 20 Febr 2001, J.Apostolakis: update for new FieldTrack +// 22 Sept 2000, V.Grichine: update of Kinetic Energy +// Created: 19 March 1997, J. Apostolakis +// ======================================================================= + +#include "G4CoupledTransportation.hh" + +#include "G4PhysicalConstants.hh" +#include "G4SystemOfUnits.hh" +#include "G4TransportationProcessType.hh" +#include "G4ProductionCutsTable.hh" +#include "G4ParticleTable.hh" +#include "G4ChordFinder.hh" +#include "G4Field.hh" +#include "G4FieldTrack.hh" +#include "G4FieldManagerStore.hh" + +class G4VSensitiveDetector; + +G4bool G4CoupledTransportation::fUseMagneticMoment=false; +////////////////////////////////////////////////////////////////////////// +// +// Constructor + +G4CoupledTransportation::G4CoupledTransportation( G4int verbosity ) + : G4VProcess( G4String("CoupledTransportation"), fTransportation ), + fTransportEndPosition(0.0, 0.0, 0.0), + fTransportEndMomentumDir(0.0, 0.0, 0.0), + fTransportEndKineticEnergy(0.0), + fTransportEndSpin(0.0, 0.0, 0.0), // fTransportEndPolarization(0.0, 0.0, 0.0), + fMomentumChanged(false), + fEndGlobalTimeComputed(false), + fCandidateEndGlobalTime(0.0), + fParticleIsLooping( false ), + fPreviousSftOrigin( 0.,0.,0. ), + fPreviousMassSafety( 0.0 ), + fPreviousFullSafety( 0.0 ), + fMassGeometryLimitedStep( false ), + fAnyGeometryLimitedStep( false ), + fEndpointDistance( -1.0 ), + fThreshold_Warning_Energy( 100 * MeV ), + fThreshold_Important_Energy( 250 * MeV ), + fThresholdTrials( 10 ), + fNoLooperTrials( 0 ), + fSumEnergyKilled( 0.0 ), fMaxEnergyKilled( 0.0 ), + fVerboseLevel( verbosity ) +{ + // set Process Sub Type + SetProcessSubType(static_cast(COUPLED_TRANSPORTATION)); + + G4TransportationManager* transportMgr ; + + transportMgr = G4TransportationManager::GetTransportationManager() ; + + fMassNavigator = transportMgr->GetNavigatorForTracking() ; + fFieldPropagator = transportMgr->GetPropagatorInField() ; + // fGlobalFieldMgr = transportMgr->GetFieldManager() ; + fNavigatorId= transportMgr->ActivateNavigator( fMassNavigator ); + if( fVerboseLevel > 0 ) + { + G4cout << " G4CoupledTransportation constructor: ----- " << G4endl; + G4cout << " Verbose level is " << fVerboseLevel << G4endl; + G4cout << " Navigator Id obtained in G4CoupledTransportation constructor " + << fNavigatorId << G4endl; + } + fPathFinder= G4PathFinder::GetInstance(); + fpSafetyHelper = transportMgr->GetSafetyHelper(); // New + + // Following assignment is to fix small memory leak from simple use of 'new' + static G4ThreadLocal G4TouchableHandle* pNullTouchableHandle = 0; + if ( !pNullTouchableHandle) { pNullTouchableHandle = new G4TouchableHandle; } + fCurrentTouchableHandle = *pNullTouchableHandle; + // Points to (G4VTouchable*) 0 + + G4FieldManager *globalFieldMgr= transportMgr->GetFieldManager(); + fGlobalFieldExists= globalFieldMgr ? globalFieldMgr->GetDetectorField() : 0 ; +} + +////////////////////////////////////////////////////////////////////////// + +G4CoupledTransportation::~G4CoupledTransportation() +{ + // fCurrentTouchableHandle is a data member - no deletion required + + if( (fVerboseLevel > 0) || (fSumEnergyKilled > 0.0 ) ) + { + G4cout << " G4CoupledTransportation: Statistics for looping particles " << G4endl; + G4cout << " Sum of energy of loopers killed: " << fSumEnergyKilled << G4endl; + G4cout << " Max energy of loopers killed: " << fMaxEnergyKilled << G4endl; + } +} + +////////////////////////////////////////////////////////////////////////// +// +// Responsibilities: +// Find whether the geometry limits the Step, and to what length +// Calculate the new value of the safety and return it. +// Store the final time, position and momentum. + +G4double G4CoupledTransportation:: +AlongStepGetPhysicalInteractionLength( const G4Track& track, + G4double, // previousStepSize + G4double currentMinimumStep, + G4double& proposedSafetyForStart, + G4GPILSelection* selection ) +{ + G4double geometryStepLength; + G4double startMassSafety= 0.0; // estimated safety for start point (mass geometry) + G4double startFullSafety= 0.0; // estimated safety for start point (all geometries) + G4double safetyProposal= -1.0; // local copy of proposal + + G4ThreeVector EndUnitMomentum ; + G4double lengthAlongCurve=0.0 ; + + fParticleIsLooping = false ; + + // Initial actions moved to StartTrack() + // -------------------------------------- + // Note: in case another process changes touchable handle + // it will be necessary to add here (for all steps) + // fCurrentTouchableHandle = aTrack->GetTouchableHandle(); + + // GPILSelection is set to defaule value of CandidateForSelection + // It is a return value + // + *selection = CandidateForSelection ; + + // Get initial Energy/Momentum of the track + // + const G4DynamicParticle* pParticle = track.GetDynamicParticle() ; + const G4ParticleDefinition* pParticleDef = pParticle->GetDefinition() ; + G4ThreeVector startMomentumDir = pParticle->GetMomentumDirection() ; + G4ThreeVector startPosition = track.GetPosition() ; + G4VPhysicalVolume* currentVolume= track.GetVolume(); + +#ifdef G4DEBUG_TRANSPORT + if( fVerboseLevel > 1 ) + { + G4cout << "G4CoupledTransportation::AlongStepGPIL> called in volume " + << currentVolume->GetName() << G4endl; + } +#endif + // G4double theTime = track.GetGlobalTime() ; + + // The Step Point safety can be limited by other geometries and/or the + // assumptions of any process - it's not always the geometrical safety. + // We calculate the starting point's isotropic safety here. + // + G4ThreeVector OriginShift = startPosition - fPreviousSftOrigin ; + G4double MagSqShift = OriginShift.mag2() ; + startMassSafety = 0.0; + startFullSafety= 0.0; + + // Recall that FullSafety <= MassSafety + // Original: if( MagSqShift < sqr(fPreviousMassSafety) ) { + if( MagSqShift < sqr(fPreviousFullSafety) ) // Revision proposed by Alex H, 2 Oct 07 + { + G4double mag_shift= std::sqrt(MagSqShift); + startMassSafety = std::max( (fPreviousMassSafety - mag_shift), 0.0); + startFullSafety = std::max( (fPreviousFullSafety - mag_shift), 0.0); + // Need to be consistent between full safety with Mass safety + // in order reproduce results in simple case --> use same calculation method + + // Only compute full safety if massSafety > 0. Else it remains 0 + // startFullSafety = fPathFinder->ComputeSafety( startPosition ); + } + + // Is the particle charged or has it a magnetic moment? + // + G4double particleCharge = pParticle->GetCharge() ; + G4double magneticMoment = pParticle->GetMagneticMoment() ; + G4double restMass = pParticle->GetMass() ; + + fMassGeometryLimitedStep = false ; // Set default - alex + fAnyGeometryLimitedStep = false; + + // fEndGlobalTimeComputed = false ; + + // There is no need to locate the current volume. It is Done elsewhere: + // On track construction + // By the tracking, after all AlongStepDoIts, in "Relocation" + + // Check if the particle has a force, EM or gravitational, exerted on it + // + G4FieldManager* fieldMgr=0; + G4bool fieldExertsForce = false ; + + G4bool gravityOn = false; + const G4Field* ptrField= 0; + + fieldMgr = fFieldPropagator->FindAndSetFieldManager( track.GetVolume() ); + if( fieldMgr != 0 ) + { + // Message the field Manager, to configure it for this track + fieldMgr->ConfigureForTrack( &track ); + // Here it can transition from a null field-ptr to a finite field + + // If the field manager has no field ptr, the field is zero + // by definition ( = there is no field ! ) + ptrField= fieldMgr->GetDetectorField(); + + if( ptrField != 0) + { + gravityOn= ptrField->IsGravityActive(); + if( (particleCharge != 0.0) + || (fUseMagneticMoment && (magneticMoment != 0.0) ) + || (gravityOn && (restMass != 0.0)) + ) + { + fieldExertsForce = true; + } + } + } + G4double momentumMagnitude = pParticle->GetTotalMomentum() ; + + if( fieldExertsForce ) + { + G4EquationOfMotion* equationOfMotion = 0; + + // equationOfMotion = + // (fFieldPropagator->GetChordFinder()->GetIntegrationDriver()->GetStepper()) + // ->GetEquationOfMotion(); + + // Consolidate into auxiliary method G4EquationOfMotion* GetEquationOfMotion() + // equationOfMotion= fFieldPropagator->GetCurrentEquationOfMotion(); + G4MagIntegratorStepper* pStepper= 0; + + G4ChordFinder* pChordFinder= fFieldPropagator->GetChordFinder(); + if( pChordFinder ) + { + G4MagInt_Driver* pIntDriver= 0; + + pIntDriver= pChordFinder->GetIntegrationDriver(); + if( pIntDriver ) + { + pStepper= pIntDriver->GetStepper(); + } + if( pStepper ) + { + equationOfMotion= pStepper->GetEquationOfMotion(); + } + } + // End of proto GetEquationOfMotion() + + G4ChargeState chargeState(particleCharge, // The charge can change (dynamic) + magneticMoment, + pParticleDef->GetPDGSpin() ); + // For insurance, could set it again + // chargeState.SetPDGSpin( pParticleDef->GetPDGSpin() ); // Newly/provisionally in same object + + if( equationOfMotion ) + { + equationOfMotion->SetChargeMomentumMass( chargeState, + momentumMagnitude, + restMass ); + }else{ + G4cerr << " ERROR > Cannot find valid Equation of motion - Unable to pass Charge, Momentum and Mass " << G4endl; + } + } + + G4ThreeVector polarizationVec = track.GetPolarization() ; + G4FieldTrack aFieldTrack = G4FieldTrack( startPosition, + track.GetGlobalTime(), // Lab. + // track.GetProperTime(), // Particle rest frame + track.GetMomentumDirection(), + track.GetKineticEnergy(), + restMass, + particleCharge, + polarizationVec, + pParticleDef->GetPDGMagneticMoment(), + 0.0, // Length along track + pParticleDef->GetPDGSpin() + ) ; + G4int stepNo= track.GetCurrentStepNumber(); + + ELimited limitedStep; + G4FieldTrack endTrackState('a'); // Default values + + fMassGeometryLimitedStep = false ; // default + fAnyGeometryLimitedStep = false ; + if( currentMinimumStep > 0 ) + { + G4double newMassSafety= 0.0; // temp. for recalculation + + // Do the Transport in the field (non recti-linear) + // + lengthAlongCurve = fPathFinder->ComputeStep( aFieldTrack, + currentMinimumStep, + fNavigatorId, + stepNo, + newMassSafety, + limitedStep, + endTrackState, + currentVolume ) ; + // G4cout << " PathFinder ComputeStep returns " << lengthAlongCurve << G4endl; + + G4double newFullSafety= fPathFinder->GetCurrentSafety(); + // this was estimated already in step above + // G4double newFullStep= fPathFinder->GetMinimumStep(); + + if( limitedStep == kUnique || limitedStep == kSharedTransport ) + { + fMassGeometryLimitedStep = true ; + } + + fAnyGeometryLimitedStep = (fPathFinder->GetNumberGeometriesLimitingStep() != 0); + +//#ifdef G4DEBUG_TRANSPORT + if( fMassGeometryLimitedStep && !fAnyGeometryLimitedStep ) + { + G4cerr << " Error in determining geometries limiting the step" << G4endl; + G4cerr << " Limiting: mass=" << fMassGeometryLimitedStep + << " any= " << fAnyGeometryLimitedStep << G4endl; + G4Exception("G4CoupledTransportation::AlongStepGetPhysicalInteractionLength()", + "PathFinderConfused", FatalException, + "Incompatible conditions - was limited by a geometry?"); + } +//#endif + + // Other potential + // fAnyGeometryLimitedStep = newFullStep < currentMinimumStep; + // ^^^ Not good enough; + // Must compare with maximum requested step size + // (eg in case another process requested bigger, got this!) + + geometryStepLength = std::min( lengthAlongCurve, currentMinimumStep); + + // Momentum: Magnitude and direction can be changed too now ... + // + fMomentumChanged = true ; + fTransportEndMomentumDir = endTrackState.GetMomentumDir() ; + + // Remember last safety origin & value. + fPreviousSftOrigin = startPosition ; + fPreviousMassSafety = newMassSafety ; + fPreviousFullSafety = newFullSafety ; + // fpSafetyHelper->SetCurrentSafety( newFullSafety, startPosition); + +#ifdef G4DEBUG_TRANSPORT + if( fVerboseLevel > 1 ) + { + G4cout << "G4Transport:CompStep> " + << " called the pathfinder for a new step at " << startPosition + << " and obtained step = " << lengthAlongCurve << G4endl; + G4cout << " New safety (preStep) = " << newMassSafety + << " versus precalculated = " << startMassSafety << G4endl; + } +#endif + + // Store as best estimate value + startMassSafety = newMassSafety ; + startFullSafety = newFullSafety ; + + // Get the End-Position and End-Momentum (Dir-ection) + fTransportEndPosition = endTrackState.GetPosition() ; + fTransportEndKineticEnergy = endTrackState.GetKineticEnergy() ; + } + else + { + geometryStepLength = lengthAlongCurve= 0.0 ; + fMomentumChanged = false ; + // fMassGeometryLimitedStep = false ; // --- ??? + // fAnyGeometryLimitedStep = true; + fTransportEndMomentumDir = track.GetMomentumDirection(); + fTransportEndKineticEnergy = track.GetKineticEnergy(); + + fTransportEndPosition = startPosition; + + endTrackState= aFieldTrack; // Ensures that time is updated + + // If the step length requested is 0, and we are on a boundary + // then a boundary will also limit the step. + if( startMassSafety == 0.0 ) + { + fMassGeometryLimitedStep = true ; + fAnyGeometryLimitedStep = true; + } + // TODO: Add explicit logical status for being at a boundary + } + // G4FieldTrack aTrackState(endTrackState); + + if( !fieldExertsForce ) + { + fParticleIsLooping = false ; + fMomentumChanged = false ; + fEndGlobalTimeComputed = false ; + // G4cout << " global time is false " << G4endl; + } + else + { + +#ifdef G4DEBUG_TRANSPORT + if( fVerboseLevel > 1 ) + { + G4cout << " G4CT::CS End Position = " << fTransportEndPosition << G4endl; + G4cout << " G4CT::CS End Direction = " << fTransportEndMomentumDir << G4endl; + } +#endif + if( fFieldPropagator->GetCurrentFieldManager()->DoesFieldChangeEnergy() ) + { + // If the field can change energy, then the time must be integrated + // - so this should have been updated + // + fCandidateEndGlobalTime = endTrackState.GetLabTimeOfFlight(); + fEndGlobalTimeComputed = true; + + // was ( fCandidateEndGlobalTime != track.GetGlobalTime() ); + // a cleaner way is to have FieldTrack knowing whether time is updated. + } + else + { + // The energy should be unchanged by field transport, + // - so the time changed will be calculated elsewhere + // + fEndGlobalTimeComputed = false; + + // Check that the integration preserved the energy + // - and if not correct this! + G4double startEnergy= track.GetKineticEnergy(); + G4double endEnergy= fTransportEndKineticEnergy; + + static G4ThreadLocal G4int no_inexact_steps=0; // , no_large_ediff; + G4double absEdiff = std::fabs(startEnergy- endEnergy); + if( absEdiff > perMillion * endEnergy ) + { + no_inexact_steps++; + // Possible statistics keeping here ... + } +#ifdef G4VERBOSE + if( (fVerboseLevel > 1) && ( absEdiff > perThousand * endEnergy) ) + { + ReportInexactEnergy(startEnergy, endEnergy); + } // end of if (fVerboseLevel) +#endif + // Correct the energy for fields that conserve it + // This - hides the integration error + // - but gives a better physical answer + fTransportEndKineticEnergy= track.GetKineticEnergy(); + } + } + + fEndpointDistance = (fTransportEndPosition - startPosition).mag() ; + fParticleIsLooping = fFieldPropagator->IsParticleLooping() ; + + fTransportEndSpin = endTrackState.GetSpin(); + + // Calculate the safety + safetyProposal= startFullSafety; // used to be startMassSafety + // Changed to accomodate processes that cannot update the safety -- JA 22 Nov 06 + + // Update safety for the end-point, if becomes negative at the end-point. + + if( (startFullSafety < fEndpointDistance ) + && ( particleCharge != 0.0 ) ) // Only needed to prepare for Mult Scat. + // && !fAnyGeometryLimitedStep ) // To-Try: No safety update if at a boundary + { + G4double endFullSafety = + fPathFinder->ComputeSafety( fTransportEndPosition); + // Expected mission -- only mass geometry's safety + // fMassNavigator->ComputeSafety( fTransportEndPosition) ; + // Yet discrete processes only have poststep -- and this cannot + // currently revise the safety + // ==> so we use the all-geometry safety as a precaution + + fpSafetyHelper->SetCurrentSafety( endFullSafety, fTransportEndPosition); + // Pushing safety to Helper avoids recalculation at this point + + G4ThreeVector centerPt= G4ThreeVector(0.0, 0.0, 0.0); // Used for return value + G4double endMassSafety= fPathFinder->ObtainSafety( fNavigatorId, centerPt); + // Retrieves the mass value from PathFinder (it calculated it) + + fPreviousMassSafety = endMassSafety ; + fPreviousFullSafety = endFullSafety; + fPreviousSftOrigin = fTransportEndPosition ; + + // The convention (Stepping Manager's) is safety from the start point + // + safetyProposal = endFullSafety + fEndpointDistance; + // --> was endMassSafety + // Changed to accomodate processes that cannot update the safety -- JA 22 Nov 06 + + // #define G4DEBUG_TRANSPORT 1 + +#ifdef G4DEBUG_TRANSPORT + G4int prec= G4cout.precision(12) ; + G4cout << "***Transportation::AlongStepGPIL ** " << G4endl ; + G4cout << " Revised Safety at endpoint " << fTransportEndPosition + << " give safety values: Mass= " << endMassSafety + << " All= " << endFullSafety << G4endl ; + G4cout << " Adding endpoint distance " << fEndpointDistance + << " to obtain pseudo-safety= " << safetyProposal << G4endl ; + G4cout.precision(prec); + } + else + { + G4int prec= G4cout.precision(12) ; + G4cout << "***Transportation::AlongStepGPIL ** " << G4endl ; + G4cout << " Quick Safety estimate at endpoint " << fTransportEndPosition + << " gives safety endpoint value = " << startFullSafety - fEndpointDistance + << " using start-point value " << startFullSafety + << " and endpointDistance " << fEndpointDistance << G4endl; + G4cout.precision(prec); +#endif + } + + proposedSafetyForStart= safetyProposal; + fParticleChange.ProposeTrueStepLength(geometryStepLength) ; + + return geometryStepLength ; +} + +////////////////////////////////////////////////////////////////////////// + +G4VParticleChange* +G4CoupledTransportation::AlongStepDoIt( const G4Track& track, + const G4Step& stepData ) +{ + static G4ThreadLocal G4int noCalls=0; + noCalls++; + + fParticleChange.Initialize(track) ; + // sets all its members to the value of corresponding members in G4Track + + // Code specific for Transport + // + fParticleChange.ProposePosition(fTransportEndPosition) ; + // G4cout << " G4CoupledTransportation::AlongStepDoIt" + // << " proposes position = " << fTransportEndPosition + // << " and end momentum direction = " << fTransportEndMomentumDir << G4endl; + fParticleChange.ProposeMomentumDirection(fTransportEndMomentumDir) ; + fParticleChange.ProposeEnergy(fTransportEndKineticEnergy) ; + fParticleChange.SetMomentumChanged(fMomentumChanged) ; + + fParticleChange.ProposePolarization(fTransportEndSpin); + + G4double deltaTime = 0.0 ; + + // Calculate Lab Time of Flight (ONLY if field Equations used it!) + // G4double endTime = fCandidateEndGlobalTime; + // G4double delta_time = endTime - startTime; + + G4double startTime = track.GetGlobalTime() ; + + if (!fEndGlobalTimeComputed) + { + G4double finalInverseVel= DBL_MAX, initialInverseVel=DBL_MAX; + + // The time was not integrated .. make the best estimate possible + // + G4double finalVelocity = track.GetVelocity() ; + if( finalVelocity > 0.0 ) { finalInverseVel= 1.0 / finalVelocity; } + G4double initialVelocity = stepData.GetPreStepPoint()->GetVelocity() ; + if( initialVelocity > 0.0 ) { initialInverseVel= 1.0 / initialVelocity; } + G4double stepLength = track.GetStepLength() ; + + if (finalVelocity > 0.0) + { + // deltaTime = stepLength/finalVelocity ; + G4double meanInverseVelocity = 0.5 * ( initialInverseVel + finalInverseVel ); + deltaTime = stepLength * meanInverseVelocity ; + // G4cout << " dt = s * mean(1/v) , with " << " s = " << stepLength + // << " mean(1/v)= " << meanInverseVelocity << G4endl; + } + else + { + deltaTime = stepLength * initialInverseVel ; + // G4cout << " dt = s / initV " << " s = " << stepLength + // << " 1 / initV= " << initialInverseVel << G4endl; + } // Could do with better estimate for final step (finalVelocity = 0) ? + + fCandidateEndGlobalTime = startTime + deltaTime ; + fParticleChange.ProposeLocalTime( track.GetLocalTime() + deltaTime) ; + + // G4cout << " Calculated global time from start = " << startTime << " and " + // << " delta time = " << deltaTime << G4endl; + } + else + { + deltaTime = fCandidateEndGlobalTime - startTime ; + fParticleChange.ProposeGlobalTime( fCandidateEndGlobalTime ) ; + // G4cout << " Calculated global time from candidate end time = " + // << fCandidateEndGlobalTime << " and start time = " << startTime << G4endl; + } + + // G4cout << " G4CoupledTransportation::AlongStepDoIt " + // << " flag whether computed time = " << fEndGlobalTimeComputed << " and " + // << " is proposes end time " << fCandidateEndGlobalTime << G4endl; + + // Now Correct by Lorentz factor to get "proper" deltaTime + + G4double restMass = track.GetDynamicParticle()->GetMass() ; + G4double deltaProperTime = deltaTime*( restMass/track.GetTotalEnergy() ) ; + + fParticleChange.ProposeProperTime(track.GetProperTime() + deltaProperTime) ; + //fParticleChange. ProposeTrueStepLength( track.GetStepLength() ) ; + + // If the particle is caught looping or is stuck (in very difficult + // boundaries) in a magnetic field (doing many steps) + // THEN this kills it ... + // + if ( fParticleIsLooping ) + { + G4double endEnergy= fTransportEndKineticEnergy; + + if( (endEnergy < fThreshold_Important_Energy) + || (fNoLooperTrials >= fThresholdTrials ) ) + { + // Kill the looping particle + // + fParticleChange.ProposeTrackStatus( fStopAndKill ) ; + + // 'Bare' statistics + fSumEnergyKilled += endEnergy; + if( endEnergy > fMaxEnergyKilled) { fMaxEnergyKilled= endEnergy; } + +#ifdef G4VERBOSE + if((fVerboseLevel > 1) && ( endEnergy > fThreshold_Warning_Energy )) + { + G4cout << " G4CoupledTransportation is killing track that is looping or stuck " << G4endl + << " This track has " << track.GetKineticEnergy() / MeV + << " MeV energy." << G4endl; + } + if( fVerboseLevel > 0 ) + { + G4cout << " Steps by this track: " << track.GetCurrentStepNumber() << G4endl; + } +#endif + fNoLooperTrials=0; + } + else + { + fNoLooperTrials ++; +#ifdef G4VERBOSE + if( (fVerboseLevel > 2) ) + { + G4cout << " ** G4CoupledTransportation::AlongStepDoIt(): Particle looping - " << G4endl + << " Number of consecutive problem step (this track) = " << fNoLooperTrials << G4endl + << " Steps by this track: " << track.GetCurrentStepNumber() << G4endl + << " Total no of calls to this method (all tracks) = " << noCalls << G4endl; + } +#endif + } + } + else + { + fNoLooperTrials=0; + } + + // Another (sometimes better way) is to use a user-limit maximum Step size + // to alleviate this problem .. + + // Add smooth curved trajectories to particle-change + // + // fParticleChange.SetPointerToVectorOfAuxiliaryPoints + // (fFieldPropagator->GimmeTrajectoryVectorAndForgetIt() ); + + return &fParticleChange ; +} + +////////////////////////////////////////////////////////////////////////// +// +// This ensures that the PostStep action is always called, +// so that it can do the relocation if it is needed. +// + +G4double G4CoupledTransportation:: +PostStepGetPhysicalInteractionLength( const G4Track&, + G4double, // previousStepSize + G4ForceCondition* pForceCond ) +{ + // Must act as PostStep action -- to relocate particle + *pForceCond = Forced ; + return DBL_MAX ; +} + +void G4CoupledTransportation:: +ReportMove( G4ThreeVector OldVector, G4ThreeVector NewVector, const G4String& Quantity ) +{ + G4ThreeVector moveVec = ( NewVector - OldVector ); + + G4cerr << G4endl + << "**************************************************************" << G4endl; + G4cerr << "Endpoint has moved between value expected from TransportEndPosition " + << " and value from Track in PostStepDoIt. " << G4endl + << "Change of " << Quantity << " is " << moveVec.mag() / mm << " mm long, " + << " and its vector is " << (1.0/mm) * moveVec << " mm " << G4endl + << "Endpoint of ComputeStep was " << OldVector + << " and current position to locate is " << NewVector << G4endl; +} + +///////////////////////////////////////////////////////////////////////////// + +G4VParticleChange* G4CoupledTransportation::PostStepDoIt( const G4Track& track, + const G4Step& ) +{ + G4TouchableHandle retCurrentTouchable ; // The one to return + + // Initialize ParticleChange (by setting all its members equal + // to corresponding members in G4Track) + // fParticleChange.Initialize(track) ; // To initialise TouchableChange + + fParticleChange.ProposeTrackStatus(track.GetTrackStatus()) ; + + // Check that the end position and direction are preserved + // since call to AlongStepDoIt + +#ifdef G4DEBUG_TRANSPORT + if( ( fVerboseLevel > 0 ) + && ((fTransportEndPosition - track.GetPosition()).mag2() >= 1.0e-16) ) + { + ReportMove( track.GetPosition(), fTransportEndPosition, "End of Step Position" ); + G4cerr << " Problem in G4CoupledTransportation::PostStepDoIt " << G4endl; + } + + // If the Step was determined by the volume boundary, relocate the particle + // The pathFinder will know that the geometry limited the step (!?) + + if( fVerboseLevel > 0 ) + { + G4cout << " Calling PathFinder::Locate() from " + << " G4CoupledTransportation::PostStepDoIt " << G4endl; + G4cout << " fAnyGeometryLimitedStep is " << fAnyGeometryLimitedStep << G4endl; + + } +#endif + + if(fAnyGeometryLimitedStep) + { + fPathFinder->Locate( track.GetPosition(), + track.GetMomentumDirection(), + true); + + // fCurrentTouchable will now become the previous touchable, + // and what was the previous will be freed. + // (Needed because the preStepPoint can point to the previous touchable) + + fCurrentTouchableHandle= + fPathFinder->CreateTouchableHandle( fNavigatorId ); + +#ifdef G4DEBUG_TRANSPORT + if( fVerboseLevel > 0 ) + { + G4cout << "G4CoupledTransportation::PostStepDoIt --- fNavigatorId = " + << fNavigatorId << G4endl; + } + if( fVerboseLevel > 1 ) + { + G4VPhysicalVolume* vol= fCurrentTouchableHandle->GetVolume(); + G4cout << "CHECK !!!!!!!!!!! fCurrentTouchableHandle->GetVolume() = " << vol; + if( vol ) { G4cout << "Name=" << vol->GetName(); } + G4cout << G4endl; + } +#endif + + // Check whether the particle is out of the world volume + // If so it has exited and must be killed. + // + if( fCurrentTouchableHandle->GetVolume() == 0 ) + { + fParticleChange.ProposeTrackStatus( fStopAndKill ) ; + } + retCurrentTouchable = fCurrentTouchableHandle ; + // fParticleChange.SetTouchableHandle( fCurrentTouchableHandle ) ; + + // Notify particle change that this is last step in volume + fParticleChange.ProposeLastStepInVolume(true); + } + else // fAnyGeometryLimitedStep is false + { +#ifdef G4DEBUG_TRANSPORT + if( fVerboseLevel > 1 ) + { + G4cout << "G4CoupledTransportation::PostStepDoIt -- " + << " fAnyGeometryLimitedStep = " << fAnyGeometryLimitedStep + << " must be false " << G4endl; + } +#endif + // This serves only to move each of the Navigator's location + // + // fLinearNavigator->LocateGlobalPointWithinVolume( track.GetPosition() ) ; + + // G4cout << "G4CoupledTransportation calling PathFinder::ReLocate() " << G4endl; + fPathFinder->ReLocate( track.GetPosition() ); + // track.GetMomentumDirection() ); + + // Keep the value of the track's current Touchable is retained, + // and use it to overwrite the (unset) one in particle change. + // Expect this must be fCurrentTouchable too + // - could it be different, eg at the start of a step ? + // + retCurrentTouchable = track.GetTouchableHandle() ; + // fParticleChange.SetTouchableHandle( track.GetTouchableHandle() ) ; + + // Have not reached a boundary + fParticleChange.ProposeLastStepInVolume(false); + } // endif ( fAnyGeometryLimitedStep ) + + const G4VPhysicalVolume* pNewVol = retCurrentTouchable->GetVolume() ; + const G4Material* pNewMaterial = 0 ; + const G4VSensitiveDetector* pNewSensitiveDetector = 0 ; + + if( pNewVol != 0 ) + { + pNewMaterial= pNewVol->GetLogicalVolume()->GetMaterial(); + pNewSensitiveDetector= pNewVol->GetLogicalVolume()->GetSensitiveDetector(); + } + + // ( const_cast pNewMaterial ) ; + // ( const_cast pNewSensitiveDetector) ; + + fParticleChange.SetMaterialInTouchable( (G4Material *) pNewMaterial ) ; + fParticleChange.SetSensitiveDetectorInTouchable( (G4VSensitiveDetector *) pNewSensitiveDetector ) ; + // "temporarily" until Get/Set Material of ParticleChange, + // and StepPoint can be made const. + + const G4MaterialCutsCouple* pNewMaterialCutsCouple = 0; + if( pNewVol != 0 ) + { + pNewMaterialCutsCouple=pNewVol->GetLogicalVolume()->GetMaterialCutsCouple(); + if( pNewMaterialCutsCouple!=0 + && pNewMaterialCutsCouple->GetMaterial()!=pNewMaterial ) + { + // for parametrized volume + // + pNewMaterialCutsCouple = + G4ProductionCutsTable::GetProductionCutsTable() + ->GetMaterialCutsCouple(pNewMaterial, + pNewMaterialCutsCouple->GetProductionCuts()); + } + } + fParticleChange.SetMaterialCutsCoupleInTouchable( pNewMaterialCutsCouple ); + + // Must always set the touchable in ParticleChange, whether relocated or not + fParticleChange.SetTouchableHandle(retCurrentTouchable) ; + + return &fParticleChange ; +} + +// New method takes over the responsibility to reset the state of +// G4CoupledTransportation object: +// - at the start of a new track, and +// - on the resumption of a suspended track. + +void +G4CoupledTransportation::StartTracking(G4Track* aTrack) +{ + + G4TransportationManager* transportMgr = + G4TransportationManager::GetTransportationManager(); + + // G4VProcess::StartTracking(aTrack); + + // The 'initialising' actions + // once taken in AlongStepGPIL -- if ( track.GetCurrentStepNumber()==1 ) + + // fStartedNewTrack= true; + + fMassNavigator = transportMgr->GetNavigatorForTracking() ; + fNavigatorId= transportMgr->ActivateNavigator( fMassNavigator ); // Confirm it! + + // if( fVerboseLevel > 1 ){ + // G4cout << " Navigator Id obtained in StartTracking " << fNavigatorId << G4endl; + // } + G4ThreeVector position = aTrack->GetPosition(); + G4ThreeVector direction = aTrack->GetMomentumDirection(); + + // if( fVerboseLevel > 1 ){ + // G4cout << " Calling PathFinder::PrepareNewTrack from " + // << " G4CoupledTransportation::StartTracking -- which calls Locate()" << G4endl; + // } + fPathFinder->PrepareNewTrack( position, direction); + // This implies a call to fPathFinder->Locate( position, direction ); + + // Global field, if any, must exist before tracking is started + fGlobalFieldExists= DoesGlobalFieldExist(); + // reset safety value and center + // + fPreviousMassSafety = 0.0 ; + fPreviousFullSafety = 0.0 ; + fPreviousSftOrigin = G4ThreeVector(0.,0.,0.) ; + + // reset looping counter -- for motion in field + fNoLooperTrials= 0; + // Must clear this state .. else it depends on last track's value + // --> a better solution would set this from state of suspended track TODO ? + // Was if( aTrack->GetCurrentStepNumber()==1 ) { .. } + + // ChordFinder reset internal state + // + if( fFieldPropagator ) + { + fFieldPropagator->ClearPropagatorState(); + // Resets safety values, in case of overlaps. + + G4ChordFinder* chordF= fFieldPropagator->GetChordFinder(); + if( chordF ) { chordF->ResetStepEstimate(); } + } + + // Clear the chord finders of all fields (ie managers) derived objects + // + G4FieldManagerStore* fieldMgrStore = G4FieldManagerStore::GetInstance(); + fieldMgrStore->ClearAllChordFindersState(); + +#ifdef G4DEBUG_TRANSPORT + if( fVerboseLevel > 1 ) + { + G4cout << " Returning touchable handle " << fCurrentTouchableHandle << G4endl; + } +#endif + + // Update the current touchable handle (from the track's) + // + fCurrentTouchableHandle = aTrack->GetTouchableHandle(); +} + +void +G4CoupledTransportation::EndTracking() +{ + G4TransportationManager::GetTransportationManager()->InactivateAll(); + fPathFinder->EndTrack(); // Resets TransportationManager to use ordinary Navigator +} + +void +G4CoupledTransportation:: +ReportInexactEnergy(G4double startEnergy, G4double endEnergy) +{ + static G4ThreadLocal G4int no_warnings= 0, warnModulo=1, moduloFactor= 10, no_large_ediff= 0; + + if( std::fabs(startEnergy- endEnergy) > perThousand * endEnergy ) + { + no_large_ediff ++; + if( (no_large_ediff% warnModulo) == 0 ) + { + no_warnings++; + G4cout << "WARNING - G4CoupledTransportation::AlongStepGetPIL() " + << " Energy change in Step is above 1^-3 relative value. " << G4endl + << " Relative change in 'tracking' step = " + << std::setw(15) << (endEnergy-startEnergy)/startEnergy << G4endl + << " Starting E= " << std::setw(12) << startEnergy / MeV << " MeV " << G4endl + << " Ending E= " << std::setw(12) << endEnergy / MeV << " MeV " << G4endl; + G4cout << " Energy has been corrected -- however, review" + << " field propagation parameters for accuracy." << G4endl; + if( (fVerboseLevel > 2 ) || (no_warnings<4) || (no_large_ediff == warnModulo * moduloFactor) ) + { + G4cout << " These include EpsilonStepMax(/Min) in G4FieldManager " + << " which determine fractional error per step for integrated quantities. " << G4endl + << " Note also the influence of the permitted number of integration steps." + << G4endl; + } + G4cerr << "ERROR - G4CoupledTransportation::AlongStepGetPIL()" << G4endl + << " Bad 'endpoint'. Energy change detected" + << " and corrected. " + << " Has occurred already " + << no_large_ediff << " times." << G4endl; + if( no_large_ediff == warnModulo * moduloFactor ) + { + warnModulo *= moduloFactor; + } + } + } +} + +#include "G4Transportation.hh" +G4bool G4CoupledTransportation::EnableUseMagneticMoment(G4bool useMoment) +{ + G4bool lastValue= fUseMagneticMoment; + fUseMagneticMoment= useMoment; + G4Transportation::fUseMagneticMoment= useMoment; + return lastValue; +} diff --git a/src/G4.10.02.p02fixes/G4IntersectingCone.cc b/src/G4.10.02.p02fixes/G4IntersectingCone.cc index c752584..5acbc79 100644 --- a/src/G4.10.02.p02fixes/G4IntersectingCone.cc +++ b/src/G4.10.02.p02fixes/G4IntersectingCone.cc @@ -24,9 +24,8 @@ // ******************************************************************** // // -// $Id: G4IntersectingCone.cc 97516 2016-06-03 14:01:05Z gcosmo $ // -// +// // -------------------------------------------------------------------- // GEANT 4 class source file // @@ -45,45 +44,31 @@ // G4IntersectingCone::G4IntersectingCone( const G4double r[2], const G4double z[2] ) -{ +{ const G4double halfCarTolerance = 0.5 * G4GeometryTolerance::GetInstance()->GetSurfaceTolerance(); - // // What type of cone are we? // - type1 = (std::fabs(z[1]-z[0]) > std::fabs(r[1]-r[0])); - - if (type1) + type1 = (std::abs(z[1]-z[0]) > std::abs(r[1]-r[0])); + + if (type1) // tube like { - B = (r[1]-r[0])/(z[1]-z[0]); // tube like - A = 0.5*( r[1]+r[0] - B*(z[1]+z[0]) ); + B = (r[1] - r[0]) / (z[1] - z[0]); + A = (r[0]*z[1] - r[1]*z[0]) / (z[1] -z[0]); } - else + else // disk like { - B = (z[1]-z[0])/(r[1]-r[0]); // disk like - A = 0.5*( z[1]+z[0] - B*(r[1]+r[0]) ); + B = (z[1] - z[0]) / (r[1] - r[0]); + A = (z[0]*r[1] - z[1]*r[0]) / (r[1] - r[0]); } - // + // Calculate extent // - if (r[0] < r[1]) - { - rLo = r[0]-halfCarTolerance; rHi = r[1]+halfCarTolerance; - } - else - { - rLo = r[1]-halfCarTolerance; rHi = r[0]+halfCarTolerance; - } - - if (z[0] < z[1]) - { - zLo = z[0]-halfCarTolerance; zHi = z[1]+halfCarTolerance; - } - else - { - zLo = z[1]-halfCarTolerance; zHi = z[0]+halfCarTolerance; - } + rLo = std::min(r[0], r[1]) - halfCarTolerance; + rHi = std::max(r[0], r[1]) + halfCarTolerance; + zLo = std::min(z[0], z[1]) - halfCarTolerance; + zHi = std::max(z[0], z[1]) + halfCarTolerance; } @@ -172,11 +157,11 @@ G4int G4IntersectingCone::LineHitsCone( const G4ThreeVector &p, // // where: // -// a = x0**2 + y0**2 - (A + B*z0)**2 +// a = tx**2 + ty**2 - (B*tz)**2 // -// b = 2*( x0*tx + y0*ty - (A*B - B*B*z0)*tz) +// b = 2*( px*vx + py*vy - B*(A + B*pz)*vz ) // -// c = tx**2 + ty**2 - (B*tz)**2 +// c = x0**2 + y0**2 - (A + B*z0)**2 // // Notice, that if a < 0, this indicates that the two solutions (assuming // they exist) are in opposite cones (that is, given z0 = -A/B, one z < z0 @@ -192,7 +177,7 @@ G4int G4IntersectingCone::LineHitsCone( const G4ThreeVector &p, // This should be rare. // // For b*b - 4*a*c = 0, we also have one solution, which is almost always -// a line just grazing the surface of a the cone, which we want to ignore. +// a line just grazing the surface of a the cone, which we want to ignore. // However, there are two other, very rare, possibilities: // a line intersecting the z axis and either: // 1. At the same angle std::atan(B) to just miss one side of the cone, or @@ -205,12 +190,12 @@ G4int G4IntersectingCone::LineHitsCone( const G4ThreeVector &p, // // Now: x0*tx + y0*ty = 0 in terms of roundoff error. We can write: // Delta = x0*tx + y0*ty -// b = 2*( Delta - (A*B + B*B*z0)*tz ) +// b = 2*( Delta - B*(A + B*z0)*tz ) // For: // b*b - 4*a*c = epsilon // where epsilon is small, then: // Delta = epsilon/2/B -// +// G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, const G4ThreeVector &v, G4double *s1, G4double *s2 ) @@ -220,15 +205,35 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); G4double tx = v.x(), ty = v.y(), tz = v.z(); - G4double a = tx*tx + ty*ty - sqr(B*tz); - G4double b = 2*( x0*tx + y0*ty - (A*B + B*B*z0)*tz); - G4double c = x0*x0 + y0*y0 - sqr(A + B*z0); - - G4double radical = b*b - 4*a*c; - - if (radical < -EPS*EPS*b*b) { return 0; } // No solution - - if (radical < EPS*EPS*b*b) + // Value of radical can be inaccurate due to loss of precision + // if to calculate the coefficiets a,b,c like the following: + // G4double a = tx*tx + ty*ty - sqr(B*tz); + // G4double b = 2*( x0*tx + y0*ty - B*(A + B*z0)*tz); + // G4double c = x0*x0 + y0*y0 - sqr(A + B*z0); + // + // For more accurate calculation of radical the coefficients + // are splitted in two components, radial and along z-axis + // + G4double ar = tx*tx + ty*ty; + G4double az = sqr(B*tz); + G4double br = 2*(x0*tx + y0*ty); + G4double bz = 2*B*(A + B*z0)*tz; + G4double cr = x0*x0 + y0*y0; + G4double cz = sqr(A + B*z0); + + // Instead radical = b*b - 4*a*c + G4double arcz = 4*ar*cz; + G4double azcr = 4*az*cr; + G4double radical = (br*br - 4*ar*cr) + ((std::max(arcz,azcr) - 2*bz*br) + std::min(arcz,azcr)); + + // Find the coefficients + G4double a = ar - az; + G4double b = br - bz; + G4double c = cr - cz; + + if (radical < -EPS*std::fabs(b)) { return 0; } // No solution + + if (radical < EPS*std::fabs(b)) { // // The radical is roughly zero: check for special, very rare, cases @@ -236,7 +241,7 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, if (std::fabs(a) > 1/kInfinity) { if(B==0.) { return 0; } - if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/(B+1e-99)) ) + if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/B) ) { *s1 = -0.5*b/a; return 1; @@ -248,7 +253,7 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, { radical = std::sqrt(radical); } - + if (a > 1/kInfinity) { G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); @@ -278,7 +283,7 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, } } - + // // LineHitsCone2 // @@ -298,7 +303,7 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, // // a > 0 now means we intersect only once in the correct hemisphere. // -// a > 0 ? We only want solution which produces R > 0. +// a > 0 ? We only want solution which produces R > 0. // since R = (z0+s*tz-A)/B, for tz/B > 0, this is the largest s // for tz/B < 0, this is the smallest s // thus, same as in case 1 ( since sign(tz/B) = sign(tz*B) ) @@ -311,36 +316,55 @@ G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, // originally it was 1E-6 G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); G4double tx = v.x(), ty = v.y(), tz = v.z(); - - + // Special case which might not be so rare: B = 0 (precisely) // if (B==0) { if (std::fabs(tz) < 1/kInfinity) { return 0; } - + *s1 = (A-z0)/tz; return 1; } + // Value of radical can be inaccurate due to loss of precision + // if to calculate the coefficiets a,b,c like the following: + // G4double a = tz*tz - B2*(tx*tx + ty*ty); + // G4double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) ); + // G4double c = sqr(z0-A) - B2*( x0*x0 + y0*y0 ); + // + // For more accurate calculation of radical the coefficients + // are splitted in two components, radial and along z-axis + // G4double B2 = B*B; - G4double a = tz*tz - B2*(tx*tx + ty*ty); - G4double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) ); - G4double c = sqr(z0-A) - B2*( x0*x0 + y0*y0 ); - - G4double radical = b*b - 4*a*c; - - if (radical < -EPS*EPS*b*b) { return 0; } // No solution - - if (radical < EPS*EPS*b*b) + G4double az = tz*tz; + G4double ar = B2*(tx*tx + ty*ty); + G4double bz = 2*(z0-A)*tz; + G4double br = 2*B2*(x0*tx + y0*ty); + G4double cz = sqr(z0-A); + G4double cr = B2*(x0*x0 + y0*y0); + + // Instead radical = b*b - 4*a*c + G4double arcz = 4*ar*cz; + G4double azcr = 4*az*cr; + G4double radical = (br*br - 4*ar*cr) + ((std::max(arcz,azcr) - 2*bz*br) + std::min(arcz,azcr)); + + // Find the coefficients + G4double a = az - ar; + G4double b = bz - br; + G4double c = cz - cr; + + if (radical < -EPS*std::fabs(b)) { return 0; } // No solution + + if (radical < EPS*std::fabs(b)) { // // The radical is roughly zero: check for special, very rare, cases // if (std::fabs(a) > 1/kInfinity) { - if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/(B+1e-99)) ) + if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/B) ) { *s1 = -0.5*b/a; return 1; @@ -352,7 +376,7 @@ G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, { radical = std::sqrt(radical); } - + if (a < -1/kInfinity) { G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); diff --git a/src/G4.10.02.p02fixes/G4IntersectingCone.cc-mine b/src/G4.10.02.p02fixes/G4IntersectingCone.cc-mine new file mode 100644 index 0000000..6290f00 --- /dev/null +++ b/src/G4.10.02.p02fixes/G4IntersectingCone.cc-mine @@ -0,0 +1,383 @@ +// +// ******************************************************************** +// * 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: G4IntersectingCone.cc 97516 2016-06-03 14:01:05Z gcosmo $ +// +// +// -------------------------------------------------------------------- +// GEANT 4 class source file +// +// +// G4IntersectingCone.cc +// +// Implementation of a utility class which calculates the intersection +// of an arbitrary line with a fixed cone +// -------------------------------------------------------------------- + +#include "G4IntersectingCone.hh" +#include "G4GeometryTolerance.hh" + +// +// Constructor +// +G4IntersectingCone::G4IntersectingCone( const G4double r[2], + const G4double z[2] ) +{ + const G4double halfCarTolerance + = 0.5 * G4GeometryTolerance::GetInstance()->GetSurfaceTolerance(); + + // + // What type of cone are we? + // + type1 = (std::fabs(z[1]-z[0]) > std::fabs(r[1]-r[0])); + + if (type1) + { + B = (r[1]-r[0])/(z[1]-z[0]); // tube like + A = 0.5*( r[1]+r[0] - B*(z[1]+z[0]) ); + } + else + { + B = (z[1]-z[0])/(r[1]-r[0]); // disk like + A = 0.5*( z[1]+z[0] - B*(r[1]+r[0]) ); + } + // + // Calculate extent + // + if (r[0] < r[1]) + { + rLo = r[0]-halfCarTolerance; rHi = r[1]+halfCarTolerance; + } + else + { + rLo = r[1]-halfCarTolerance; rHi = r[0]+halfCarTolerance; + } + + if (z[0] < z[1]) + { + zLo = z[0]-halfCarTolerance; zHi = z[1]+halfCarTolerance; + } + else + { + zLo = z[1]-halfCarTolerance; zHi = z[0]+halfCarTolerance; + } +} + + +// +// Fake default constructor - sets only member data and allocates memory +// for usage restricted to object persistency. +// +G4IntersectingCone::G4IntersectingCone( __void__& ) + : zLo(0.), zHi(0.), rLo(0.), rHi(0.), type1(false), A(0.), B(0.) +{ +} + + +// +// Destructor +// +G4IntersectingCone::~G4IntersectingCone() +{ +} + + +// +// HitOn +// +// Check r or z extent, as appropriate, to see if the point is possibly +// on the cone. +// +G4bool G4IntersectingCone::HitOn( const G4double r, + const G4double z ) +{ + // + // Be careful! The inequalities cannot be "<=" and ">=" here without + // punching a tiny hole in our shape! + // + if (type1) + { + if (z < zLo || z > zHi) return false; + } + else + { + if (r < rLo || r > rHi) return false; + } + + return true; +} + + +// +// LineHitsCone +// +// Calculate the intersection of a line with our conical surface, ignoring +// any phi division +// +G4int G4IntersectingCone::LineHitsCone( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + if (type1) + { + return LineHitsCone1( p, v, s1, s2 ); + } + else + { + return LineHitsCone2( p, v, s1, s2 ); + } +} + + +// +// LineHitsCone1 +// +// Calculate the intersections of a line with a conical surface. Only +// suitable if zPlane[0] != zPlane[1]. +// +// Equation of a line: +// +// x = x0 + s*tx y = y0 + s*ty z = z0 + s*tz +// +// Equation of a conical surface: +// +// x**2 + y**2 = (A + B*z)**2 +// +// Solution is quadratic: +// +// a*s**2 + b*s + c = 0 +// +// where: +// +// a = x0**2 + y0**2 - (A + B*z0)**2 +// +// b = 2*( x0*tx + y0*ty - (A*B - B*B*z0)*tz) +// +// c = tx**2 + ty**2 - (B*tz)**2 +// +// Notice, that if a < 0, this indicates that the two solutions (assuming +// they exist) are in opposite cones (that is, given z0 = -A/B, one z < z0 +// and the other z > z0). For our shapes, the invalid solution is one +// which produces A + Bz < 0, or the one where Bz is smallest (most negative). +// Since Bz = B*s*tz, if B*tz > 0, we want the largest s, otherwise, +// the smaller. +// +// If there are two solutions on one side of the cone, we want to make +// sure that they are on the "correct" side, that is A + B*z0 + s*B*tz >= 0. +// +// If a = 0, we have a linear problem: s = c/b, which again gives one solution. +// This should be rare. +// +// For b*b - 4*a*c = 0, we also have one solution, which is almost always +// a line just grazing the surface of a the cone, which we want to ignore. +// However, there are two other, very rare, possibilities: +// a line intersecting the z axis and either: +// 1. At the same angle std::atan(B) to just miss one side of the cone, or +// 2. Intersecting the cone apex (0,0,-A/B) +// We *don't* want to miss these! How do we identify them? Well, since +// this case is rare, we can at least swallow a little more CPU than we would +// normally be comfortable with. Intersection with the z axis means +// x0*ty - y0*tx = 0. Case (1) means a==0, and we've already dealt with that +// above. Case (2) means a < 0. +// +// Now: x0*tx + y0*ty = 0 in terms of roundoff error. We can write: +// Delta = x0*tx + y0*ty +// b = 2*( Delta - (A*B + B*B*z0)*tz ) +// For: +// b*b - 4*a*c = epsilon +// where epsilon is small, then: +// Delta = epsilon/2/B +// +G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + static const G4double EPS = DBL_EPSILON; // Precision constant, + // originally it was 1E-6 + G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); + G4double tx = v.x(), ty = v.y(), tz = v.z(); + + G4double a = tx*tx + ty*ty - sqr(B*tz); + G4double b = 2*( x0*tx + y0*ty - (A*B + B*B*z0)*tz); + G4double c = x0*x0 + y0*y0 - sqr(A + B*z0); + + G4double radical = b*b - 4*a*c; + + if (radical < -EPS*EPS*b*b) { return 0; } // No solution + + if (radical < EPS*EPS*b*b) + { + // + // The radical is roughly zero: check for special, very rare, cases + // + if (std::fabs(a) > 1/kInfinity) + { + //if(B==0.) { return 0; } + //if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/(B+1e-99)) ) + { + *s1 = -0.5*b/a; + return 1; + } + return 0; + } + } + else + { + radical = std::sqrt(radical); + } + + if (a > 1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + if (sa < sb) { *s1 = sa; *s2 = sb; } else { *s1 = sb; *s2 = sa; } + if (A + B*(z0+(*s1)*tz) < 0) { return 0; } + return 2; + } + else if (a < -1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + *s1 = (B*tz > 0)^(sa > sb) ? sb : sa; + return 1; + } + else if (std::fabs(b) < 1/kInfinity) + { + return 0; + } + else + { + *s1 = -c/b; + if (A + B*(z0+(*s1)*tz) < 0) { return 0; } + return 1; + } +} + + +// +// LineHitsCone2 +// +// See comments under LineHitsCone1. In this routine, case2, we have: +// +// Z = A + B*R +// +// The solution is still quadratic: +// +// a = tz**2 - B*B*(tx**2 + ty**2) +// +// b = 2*( (z0-A)*tz - B*B*(x0*tx+y0*ty) ) +// +// c = ( (z0-A)**2 - B*B*(x0**2 + y0**2) ) +// +// The rest is much the same, except some details. +// +// a > 0 now means we intersect only once in the correct hemisphere. +// +// a > 0 ? We only want solution which produces R > 0. +// since R = (z0+s*tz-A)/B, for tz/B > 0, this is the largest s +// for tz/B < 0, this is the smallest s +// thus, same as in case 1 ( since sign(tz/B) = sign(tz*B) ) +// +G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + static const G4double EPS = DBL_EPSILON; // Precision constant, + // originally it was 1E-6 + G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); + G4double tx = v.x(), ty = v.y(), tz = v.z(); + + + // Special case which might not be so rare: B = 0 (precisely) + // + if (B==0) + { + if (std::fabs(tz) < 1/kInfinity) { return 0; } + + *s1 = (A-z0)/tz; + return 1; + } + + G4double B2 = B*B; + + G4double a = tz*tz - B2*(tx*tx + ty*ty); + G4double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) ); + G4double c = sqr(z0-A) - B2*( x0*x0 + y0*y0 ); + + G4double radical = b*b - 4*a*c; + + if (radical < -EPS*EPS*b*b) { return 0; } // No solution + + if (radical < EPS*EPS*b*b) + { + // + // The radical is roughly zero: check for special, very rare, cases + // + if (std::fabs(a) > 1/kInfinity) + { + //if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/(B+1e-99)) ) + { + *s1 = -0.5*b/a; + return 1; + } + return 0; + } + } + else + { + radical = std::sqrt(radical); + } + + if (a < -1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + if (sa < sb) { *s1 = sa; *s2 = sb; } else { *s1 = sb; *s2 = sa; } + if ((z0 + (*s1)*tz - A)/B < 0) { return 0; } + return 2; + } + else if (a > 1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + *s1 = (tz*B > 0)^(sa > sb) ? sb : sa; + return 1; + } + else if (std::fabs(b) < 1/kInfinity) + { + return 0; + } + else + { + *s1 = -c/b; + if ((z0 + (*s1)*tz - A)/B < 0) { return 0; } + return 1; + } +} diff --git a/src/G4.10.02.p02fixes/G4ParallelWorldProcess.cc b/src/G4.10.02.p02fixes/G4ParallelWorldProcess.cc new file mode 100644 index 0000000..ed2f3b7 --- /dev/null +++ b/src/G4.10.02.p02fixes/G4ParallelWorldProcess.cc @@ -0,0 +1,454 @@ +// +// ******************************************************************** +// * 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: G4ParallelWorldProcess.cc 95501 2016-02-12 11:01:30Z gcosmo $ +// GEANT4 tag $Name: geant4-09-04-ref-00 $ +// +// + +#include "G4ios.hh" +#include "G4ParallelWorldProcess.hh" +#include "G4ParallelWorldProcessStore.hh" +#include "G4Step.hh" +#include "G4StepPoint.hh" +#include "G4Navigator.hh" +#include "G4VTouchable.hh" +#include "G4VPhysicalVolume.hh" +#include "G4ParticleChange.hh" +#include "G4PathFinder.hh" +#include "G4TransportationManager.hh" +#include "G4ParticleChange.hh" +#include "G4StepPoint.hh" +#include "G4FieldTrackUpdator.hh" +#include "G4Material.hh" +#include "G4ProductionCuts.hh" +#include "G4ProductionCutsTable.hh" + +#include "G4SDManager.hh" +#include "G4VSensitiveDetector.hh" + +G4ThreadLocal G4Step* G4ParallelWorldProcess::fpHyperStep = 0; +G4ThreadLocal G4int G4ParallelWorldProcess::nParallelWorlds = 0; +G4ThreadLocal G4int G4ParallelWorldProcess::fNavIDHyp = 0; +const G4Step* G4ParallelWorldProcess::GetHyperStep() +{ return fpHyperStep; } +G4int G4ParallelWorldProcess::GetHypNavigatorID() +{ return fNavIDHyp; } + +G4ParallelWorldProcess:: +G4ParallelWorldProcess(const G4String& processName,G4ProcessType theType) +:G4VProcess(processName,theType),fGhostWorld(nullptr),fGhostNavigator(nullptr), + fNavigatorID(-1),fFieldTrack('0'),fGhostSafety(0.),fOnBoundary(false), + layeredMaterialFlag(false) +{ + SetProcessSubType(491); + if(!fpHyperStep) fpHyperStep = new G4Step(); + iParallelWorld = ++nParallelWorlds; + + pParticleChange = &aDummyParticleChange; + + fGhostStep = new G4Step(); + fGhostPreStepPoint = fGhostStep->GetPreStepPoint(); + fGhostPostStepPoint = fGhostStep->GetPostStepPoint(); + + fTransportationManager = G4TransportationManager::GetTransportationManager(); + fTransportationManager->GetNavigatorForTracking()->SetPushVerbosity(false); + fPathFinder = G4PathFinder::GetInstance(); + + fGhostWorldName = "** NotDefined **"; + G4ParallelWorldProcessStore::GetInstance()->SetParallelWorld(this,processName); + + if (verboseLevel>0) + { + G4cout << GetProcessName() << " is created " << G4endl; + } +} + +G4ParallelWorldProcess::~G4ParallelWorldProcess() +{ + delete fGhostStep; + nParallelWorlds--; + if(nParallelWorlds==0) + { + delete fpHyperStep; + fpHyperStep = 0; + } +} + +void G4ParallelWorldProcess:: +SetParallelWorld(G4String parallelWorldName) +{ + fGhostWorldName = parallelWorldName; + fGhostWorld = fTransportationManager->GetParallelWorld(fGhostWorldName); + fGhostNavigator = fTransportationManager->GetNavigator(fGhostWorld); + fGhostNavigator->SetPushVerbosity(false); +} + +void G4ParallelWorldProcess:: +SetParallelWorld(G4VPhysicalVolume* parallelWorld) +{ + fGhostWorldName = parallelWorld->GetName(); + fGhostWorld = parallelWorld; + fGhostNavigator = fTransportationManager->GetNavigator(fGhostWorld); + fGhostNavigator->SetPushVerbosity(false); +} + +void G4ParallelWorldProcess::StartTracking(G4Track* trk) +{ + if(fGhostNavigator) + { fNavigatorID = fTransportationManager->ActivateNavigator(fGhostNavigator); } + else + { + G4Exception("G4ParallelWorldProcess::StartTracking", + "ProcParaWorld000",FatalException, + "G4ParallelWorldProcess is used for tracking without having a parallel world assigned"); + } + fPathFinder->PrepareNewTrack(trk->GetPosition(),trk->GetMomentumDirection()); + + fOldGhostTouchable = fPathFinder->CreateTouchableHandle(fNavigatorID); + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fNewGhostTouchable = fOldGhostTouchable; + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + + fGhostSafety = -1.; + fOnBoundary = false; + fGhostPreStepPoint->SetStepStatus(fUndefined); + fGhostPostStepPoint->SetStepStatus(fUndefined); + +// G4VPhysicalVolume* thePhys = fNewGhostTouchable->GetVolume(); +// if(thePhys) +// { +// G4Material* ghostMaterial = thePhys->GetLogicalVolume()->GetMaterial(); +// if(ghostMaterial) +// { G4cout << " --- Material : " << ghostMaterial->GetName() << G4endl; } +// } + + *(fpHyperStep->GetPostStepPoint()) = *(trk->GetStep()->GetPostStepPoint()); + if(layeredMaterialFlag) + { + G4StepPoint* realWorldPostStepPoint = trk->GetStep()->GetPostStepPoint(); + SwitchMaterial(realWorldPostStepPoint); + G4StepPoint *realWorldPreStepPoint = trk->GetStep()->GetPreStepPoint(); + SwitchMaterial(realWorldPreStepPoint); + G4double velocity = trk->CalculateVelocity(); + realWorldPostStepPoint->SetVelocity(velocity); + realWorldPreStepPoint->SetVelocity(velocity); + trk->SetVelocity(velocity); + } + *(fpHyperStep->GetPreStepPoint()) = *(fpHyperStep->GetPostStepPoint()); +} + +G4double +G4ParallelWorldProcess::AtRestGetPhysicalInteractionLength( + const G4Track& /*track*/, + G4ForceCondition* condition) +{ +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// At Rest must be registered ONLY for the particle which has other At Rest +// process(es). +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + *condition = Forced; + return DBL_MAX; +} + +G4VParticleChange* G4ParallelWorldProcess::AtRestDoIt( + const G4Track& track, + const G4Step& step) +{ +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// At Rest must be registered ONLY for the particle which has other At Rest +// process(es). +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fOldGhostTouchable = fGhostPostStepPoint->GetTouchableHandle(); + G4VSensitiveDetector* aSD = 0; + if(fOldGhostTouchable->GetVolume()) + { aSD = fOldGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector(); } + fOnBoundary = false; + if(aSD) + { + CopyStep(step); + fGhostPreStepPoint->SetSensitiveDetector(aSD); + + fNewGhostTouchable = fOldGhostTouchable; + + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + if(fNewGhostTouchable->GetVolume()) + { + fGhostPostStepPoint->SetSensitiveDetector( + fNewGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector()); + } + else + { fGhostPostStepPoint->SetSensitiveDetector(0); } + + aSD->Hit(fGhostStep); + } + + pParticleChange->Initialize(track); + return pParticleChange; +} + +G4double +G4ParallelWorldProcess::PostStepGetPhysicalInteractionLength( + const G4Track& /*track*/, + G4double /*previousStepSize*/, + G4ForceCondition* condition) +{ + *condition = StronglyForced; + return DBL_MAX; +} + +G4VParticleChange* G4ParallelWorldProcess::PostStepDoIt( + const G4Track& track, + const G4Step& step) +{ + fOldGhostTouchable = fGhostPostStepPoint->GetTouchableHandle(); + G4VSensitiveDetector* aSD = 0; + if(fOldGhostTouchable->GetVolume()) + { aSD = fOldGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector(); } + CopyStep(step); + fGhostPreStepPoint->SetSensitiveDetector(aSD); + + if(fOnBoundary) + { + fNewGhostTouchable = fPathFinder->CreateTouchableHandle(fNavigatorID); + } + else + { + fNewGhostTouchable = fOldGhostTouchable; + } + + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + + if(fNewGhostTouchable->GetVolume()) + { + fGhostPostStepPoint->SetSensitiveDetector( + fNewGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector()); + } + else + { fGhostPostStepPoint->SetSensitiveDetector(0); } + + G4VSensitiveDetector* sd = fGhostPreStepPoint->GetSensitiveDetector(); + if(sd) + { + sd->Hit(fGhostStep); + } + + pParticleChange->Initialize(track); + if(layeredMaterialFlag) + { + G4StepPoint* realWorldPostStepPoint = + ((G4Step*)(track.GetStep()))->GetPostStepPoint(); + SwitchMaterial(realWorldPostStepPoint); + } + return pParticleChange; +} + +G4double G4ParallelWorldProcess::AlongStepGetPhysicalInteractionLength( + const G4Track& track, G4double previousStepSize, G4double currentMinimumStep, + G4double& proposedSafety, G4GPILSelection* selection) +{ + static G4ThreadLocal G4FieldTrack *endTrack_G4MT_TLS_ = 0 ; if (!endTrack_G4MT_TLS_) endTrack_G4MT_TLS_ = new G4FieldTrack ('0') ; G4FieldTrack &endTrack = *endTrack_G4MT_TLS_; + //static ELimited eLimited; + ELimited eLimited; + ELimited eLim = kUndefLimited; + + *selection = NotCandidateForSelection; + G4double returnedStep = DBL_MAX; + + if (previousStepSize > 0.) + { fGhostSafety -= previousStepSize; } + if (fGhostSafety < 0.) fGhostSafety = 0.0; + + if (currentMinimumStep <= fGhostSafety && currentMinimumStep > 0.) + { + // I have no chance to limit + returnedStep = currentMinimumStep; + fOnBoundary = false; + proposedSafety = fGhostSafety - currentMinimumStep; + eLim = kDoNot; + } + else + { + G4FieldTrackUpdator::Update(&fFieldTrack,&track); + +#ifdef G4DEBUG_PARALLEL_WORLD_PROCESS + if( verboseLevel > 0 ){ + int localVerb = verboseLevel-1; + + if( localVerb == 1 ) { + G4cout << " Pll Wrl proc::AlongStepGPIL " << this->GetProcessName() << G4endl; + }else if( localVerb > 1 ) { + G4cout << "----------------------------------------------" << G4endl; + G4cout << " ParallelWorldProcess: field Track set to : " << G4endl; + G4cout << "----------------------------------------------" << G4endl; + G4cout << fFieldTrack << G4endl; + G4cout << "----------------------------------------------" << G4endl; + } + } +#endif + + returnedStep + = fPathFinder->ComputeStep(fFieldTrack,currentMinimumStep,fNavigatorID, + track.GetCurrentStepNumber(),fGhostSafety,eLimited, + endTrack,track.GetVolume()); + if(eLimited == kDoNot) + { + fOnBoundary = false; + fGhostSafety = fGhostNavigator->ComputeSafety(endTrack.GetPosition()); + } + else + { + fOnBoundary = true; + // fGhostSafetyEnd = 0.0; // At end-point of expected step only + } + proposedSafety = fGhostSafety; + if(eLimited == kUnique || eLimited == kSharedOther) { + *selection = CandidateForSelection; + } + else if (eLimited == kSharedTransport) { + returnedStep *= (1.0 + 1.0e-9); + } + eLim = eLimited; + } + + if(iParallelWorld==nParallelWorlds) fNavIDHyp = 0; + if(eLim == kUnique || eLim == kSharedOther) fNavIDHyp = fNavigatorID; + return returnedStep; +} + +G4VParticleChange* G4ParallelWorldProcess::AlongStepDoIt( + const G4Track& track, const G4Step& ) +{ + pParticleChange->Initialize(track); + return pParticleChange; +} + +void G4ParallelWorldProcess::CopyStep(const G4Step & step) +{ + G4StepStatus prevStat = fGhostPostStepPoint->GetStepStatus(); + + fGhostStep->SetTrack(step.GetTrack()); + fGhostStep->SetStepLength(step.GetStepLength()); + fGhostStep->SetTotalEnergyDeposit(step.GetTotalEnergyDeposit()); + fGhostStep->SetNonIonizingEnergyDeposit(step.GetNonIonizingEnergyDeposit()); + fGhostStep->SetControlFlag(step.GetControlFlag()); + + *fGhostPreStepPoint = *(step.GetPreStepPoint()); + *fGhostPostStepPoint = *(step.GetPostStepPoint()); + + fGhostPreStepPoint->SetStepStatus(prevStat); + if(fOnBoundary) + { fGhostPostStepPoint->SetStepStatus(fGeomBoundary); } + else if(fGhostPostStepPoint->GetStepStatus()==fGeomBoundary) + { fGhostPostStepPoint->SetStepStatus(fPostStepDoItProc); } + + if(iParallelWorld==1) + { + G4StepStatus prevStatHyp = fpHyperStep->GetPostStepPoint()->GetStepStatus(); + + fpHyperStep->SetTrack(step.GetTrack()); + fpHyperStep->SetStepLength(step.GetStepLength()); + fpHyperStep->SetTotalEnergyDeposit(step.GetTotalEnergyDeposit()); + fpHyperStep->SetNonIonizingEnergyDeposit(step.GetNonIonizingEnergyDeposit()); + fpHyperStep->SetControlFlag(step.GetControlFlag()); + + *(fpHyperStep->GetPreStepPoint()) = *(fpHyperStep->GetPostStepPoint()); + *(fpHyperStep->GetPostStepPoint()) = *(step.GetPostStepPoint()); + + fpHyperStep->GetPreStepPoint()->SetStepStatus(prevStatHyp); + } + + if(fOnBoundary) + { fpHyperStep->GetPostStepPoint()->SetStepStatus(fGeomBoundary); } +} + +void G4ParallelWorldProcess::SwitchMaterial(G4StepPoint* realWorldStepPoint) +{ + if(realWorldStepPoint->GetStepStatus()==fWorldBoundary) return; + G4VPhysicalVolume* thePhys = fNewGhostTouchable->GetVolume(); + if(thePhys) + { + G4Material* ghostMaterial = thePhys->GetLogicalVolume()->GetMaterial(); + if(ghostMaterial) + { + G4Region* ghostRegion = thePhys->GetLogicalVolume()->GetRegion(); + G4ProductionCuts* prodCuts = + realWorldStepPoint->GetMaterialCutsCouple()->GetProductionCuts(); + if(ghostRegion) + { + G4ProductionCuts* ghostProdCuts = ghostRegion->GetProductionCuts(); + if(ghostProdCuts) prodCuts = ghostProdCuts; + } + const G4MaterialCutsCouple* ghostMCCouple = + G4ProductionCutsTable::GetProductionCutsTable() + ->GetMaterialCutsCouple(ghostMaterial,prodCuts); + if(ghostMCCouple) + { + realWorldStepPoint->SetMaterial(ghostMaterial); + realWorldStepPoint->SetMaterialCutsCouple(ghostMCCouple); + *(fpHyperStep->GetPostStepPoint()) = *(fGhostPostStepPoint); + fpHyperStep->GetPostStepPoint()->SetMaterial(ghostMaterial); + fpHyperStep->GetPostStepPoint()->SetMaterialCutsCouple(ghostMCCouple); + } + else + { + G4cout << "!!! MaterialCutsCouple is not found for " + << ghostMaterial->GetName() << "." << G4endl + << " Material in real world (" + << realWorldStepPoint->GetMaterial()->GetName() + << ") is used." << G4endl; + } + } + } +} + +G4bool G4ParallelWorldProcess::IsAtRestRequired(G4ParticleDefinition* partDef) +{ + G4int pdgCode = partDef->GetPDGEncoding(); + if(pdgCode==0) + { + G4String partName = partDef->GetParticleName(); + if(partName=="opticalphoton") return false; + if(partName=="geantino") return false; + if(partName=="chargedgeantino") return false; + } + else + { + if(pdgCode==22) return false; // gamma + if(pdgCode==11) return false; // electron + if(pdgCode==2212) return false; // proton + if(pdgCode==-12) return false; // anti_nu_e + if(pdgCode==12) return false; // nu_e + if(pdgCode==-14) return false; // anti_nu_mu + if(pdgCode==14) return false; // nu_mu + if(pdgCode==-16) return false; // anti_nu_tau + if(pdgCode==16) return false; // nu_tau + } + return true; +} + diff --git a/src/G4.10.02.p02fixes/G4SteppingVerbose.cc b/src/G4.10.02.p02fixes/G4SteppingVerbose.cc new file mode 100644 index 0000000..94751d8 --- /dev/null +++ b/src/G4.10.02.p02fixes/G4SteppingVerbose.cc @@ -0,0 +1,883 @@ +// +// ******************************************************************** +// * 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: G4SteppingVerbose.cc 66241 2012-12-13 18:34:42Z gunter $ +// +//--------------------------------------------------------------- +// +// G4SteppingVerbose.cc +// +// Description: +// Implementation of the G4SteppingVerbose class +// Contact: +// Questions and comments to this code should be sent to +// Katsuya Amako (e-mail: Katsuya.Amako@kek.jp) +// Takashi Sasaki (e-mail: Takashi.Sasaki@kek.jp) +// +//--------------------------------------------------------------- + +#include "G4SteppingVerbose.hh" +#include "G4SteppingManager.hh" +#include "G4ForceCondition.hh" +#include "G4SystemOfUnits.hh" +#include "G4VSensitiveDetector.hh" // Include from 'hits/digi' +#include "G4StepStatus.hh" // Include from 'tracking' + +///#define G4_USE_G4BESTUNIT_FOR_VERBOSE 1 + +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE +#include "G4UnitsTable.hh" +#else +#define G4BestUnit(a,b) a +#endif + +////////////////////////////////////////////////// +G4SteppingVerbose::G4SteppingVerbose() +////////////////////////////////////////////////// +{ +#ifdef G4_TRACKING_DEBUG + G4cout << "G4SteppingVerbose has instantiated" << G4endl; +#endif +} + +////////////////////////////////////////////////// +G4SteppingVerbose::~G4SteppingVerbose() +////////////////////////////////////////////////// +{ +} + +////////////////////////////////////////////////// +void G4SteppingVerbose::NewStep() +////////////////////////////////////////////////// +{ +} + +////////////////////////////////////////////////// +void G4SteppingVerbose::AtRestDoItInvoked() +////////////////////////////////////////////////// + { + if(Silent==1){ return; } + + G4VProcess* ptProcManager; + CopyState(); + + if(verboseLevel >= 3 ){ + G4int npt=0; + G4cout << " **List of AtRestDoIt invoked:" << G4endl; + for(size_t np=0; np < MAXofAtRestLoops; np++){ + size_t npGPIL = MAXofAtRestLoops-np-1; + if( (*fSelectedAtRestDoItVector)[npGPIL] > 0 ){ + npt++; + ptProcManager = (*fAtRestDoItVector)[np]; + int cond = (*fSelectedPostStepDoItVector)[npGPIL]; + G4cout << " # " << npt << " : " + << ptProcManager->GetProcessName() + << ptProcManager->GetProcessName() + << ((cond == Forced)? " (Forced)" : + (cond == NotForced)? " (NotForced)" : + (cond == Conditionally)? " (Conditionally)" : + (cond == ExclusivelyForced)? " (ExclusivelyForced)" : + (cond == StronglyForced)? " (StronglyForced)" : "") + << G4endl; + } + } + + G4cout << " Generated secondries # : " << fN2ndariesAtRestDoIt << G4endl; + + if( fN2ndariesAtRestDoIt > 0 ){ + G4cout << " -- List of secondaries generated : " << "(x,y,z,kE,t,PID) --" << G4endl; + for( size_t lp1=(*fSecondary).size()-fN2ndariesAtRestDoIt; + lp1<(*fSecondary).size(); lp1++) { + G4cout << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy(),"Energy") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetGlobalTime(),"Time") << " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + } + } + + if( verboseLevel >= 4 ){ + ShowStep(); + G4cout << G4endl; + } +} +///////////////////////////////////////////////////// +void G4SteppingVerbose::AlongStepDoItAllDone() +///////////////////////////////////////////////////// +{ + if(Silent==1){ return; } + + G4VProcess* ptProcManager; + + CopyState(); + + if(verboseLevel >= 3){ + G4cout << G4endl; + G4cout << " >>AlongStepDoIt (after all invocations):" << G4endl; + G4cout << " ++List of invoked processes " << G4endl; + + for(size_t ci=0; ciGetProcessName() << G4endl; + } + } + + ShowStep(); + G4cout << G4endl; + G4cout << " ++List of secondaries generated " + << "(x,y,z,kE,t,PID):" + << " No. of secodaries = " + << (*fSecondary).size() << G4endl; + + if((*fSecondary).size()>0){ + for(size_t lp1=0; lp1<(*fSecondary).size(); lp1++){ + G4cout << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy(),"Energy") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetGlobalTime(),"Time") << " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + } + } +} +//////////////////////////////////////////////////// +void G4SteppingVerbose::PostStepDoItAllDone() +//////////////////////////////////////////////////// +{ + if(Silent==1){ return; } + + G4VProcess* ptProcManager; + + CopyState(); + + if( (fStepStatus == fPostStepDoItProc) | + (fCondition == Forced) | + (fCondition == Conditionally) | + (fCondition == ExclusivelyForced) | + (fCondition == StronglyForced) ){ + + if(verboseLevel >= 3){ + G4int npt=0; + G4cout << G4endl; + G4cout << " **PostStepDoIt (after all invocations):" << G4endl; + G4cout << " ++List of invoked processes " << G4endl; + + for(size_t np=0; np < MAXofPostStepLoops; np++){ + size_t npGPIL = MAXofPostStepLoops-np-1; + // This PostStepDoIt is really forced to invoke, anyway. + if( (*fSelectedPostStepDoItVector)[npGPIL] > 0){ + npt++; + ptProcManager = (*fPostStepDoItVector)[np]; + int cond = (*fSelectedPostStepDoItVector)[npGPIL]; + G4cout << " " << npt << ") " + << ptProcManager->GetProcessName() + << ((cond == Forced)? " (Forced)" : + (cond == NotForced)? " (NotForced)" : + (cond == Conditionally)? " (Conditionally)" : + (cond == ExclusivelyForced)? " (ExclusivelyForced)" : + (cond == StronglyForced)? " (StronglyForced)" : "") + << G4endl; + } + } + + ShowStep(); + G4cout << G4endl; + G4cout << " ++List of secondaries generated " + << "(x,y,z,kE,t,PID):" + << " No. of secodaries = " + << (*fSecondary).size() << G4endl; + G4cout << " [Note]Secondaries from AlongStepDoIt included." << G4endl; + + if((*fSecondary).size()>0){ + for(size_t lp1=0; lp1<(*fSecondary).size(); lp1++){ + G4cout << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x() , "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y() , "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z() , "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy() , "Energy") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetGlobalTime() , "Time") << " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + } + } + } +} + +///////////////////////////////////////// +void G4SteppingVerbose::StepInfo() +///////////////////////////////////////// +{ + if(Silent==1){ return; } + if(SilentStepInfo==1){ return; } + + CopyState(); + G4cout.precision(16); + G4int prec = G4cout.precision(3); + + if( verboseLevel >= 1 ){ + if( verboseLevel >= 4 ) VerboseTrack(); + if( verboseLevel >= 3 ){ + G4cout << G4endl; +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << std::setw( 5) << "#Step#" << " " + << std::setw( 8) << "X" << " " << std::setw( 8) << "Y" << " " + << std::setw( 8) << "Z" << " " + << std::setw( 9) << "KineE" << " " << std::setw( 8) << "dE" << " " + << std::setw(12) << "StepLeng" << " " << std::setw(12) << "TrackLeng" << " " + << std::setw(12) << "NextVolume" << " " << std::setw( 8) << "ProcName" << G4endl; +#else + G4cout << std::setw( 5) << "#Step#" << " " + << std::setw( 8) << "X(mm)" << " " << std::setw( 8) << "Y(mm)" << " " + << std::setw( 8) << "Z(mm)" << " " + << std::setw( 9) << "KinE(MeV)" << " " << std::setw( 8) << "dE(MeV)" << " " + << std::setw( 8) << "StepLeng" << " " << std::setw( 9) << "TrackLeng" << " " + << std::setw(11) << "NextVolume" << " " << std::setw( 8) << "ProcName" << G4endl; +#endif + } + G4cout << std::setw( 5) << fTrack->GetCurrentStepNumber() << " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().x() , "Length") << " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().y() , "Length") << " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().z() , "Length") << " " + << std::setw( 9) << G4BestUnit(fTrack->GetKineticEnergy() , "Energy") << " " + << std::setw( 8) << G4BestUnit(fStep->GetTotalEnergyDeposit(), "Energy") << " " + << std::setw( 8) << G4BestUnit(fStep->GetStepLength() , "Length") << " " + << std::setw( 9) << G4BestUnit(fTrack->GetTrackLength() , "Length") << " "; + + // Put cut comment here + if( fTrack->GetNextVolume() != 0 ) { + G4cout << std::setw(11) << fTrack->GetNextVolume()->GetName() << " "; + } else { + G4cout << std::setw(11) << "OutOfWorld" << " "; + } + if(fStep->GetPostStepPoint()->GetProcessDefinedStep() != 0){ + G4cout << fStep->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName(); + } else { + G4cout << "User Limit"; + } + 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( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z() , "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy() , "Energy")<< " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + G4cout << " :-----------------------------" << "----------------------------------" + << "-- EndOf2ndaries Info ---------------" << G4endl; + } + } + } + G4cout.precision(prec); +} +// Put cut comment here if( fStepStatus != fWorldBoundary){ + +//////////////////////////////////////////// +void G4SteppingVerbose::DPSLStarted() +//////////////////////////////////////////// +{ + if(Silent==1){ return; } + CopyState(); + + if( verboseLevel > 5 ){ + G4cout << G4endl << " >>DefinePhysicalStepLength (List of proposed StepLengths): " << G4endl; + } +} +////////////////////////////////////////////// +void G4SteppingVerbose::DPSLUserLimit() +////////////////////////////////////////////// +{ + if(Silent==1){ return; } + CopyState(); + + if( verboseLevel > 5 ){ + G4cout << G4endl << G4endl; + G4cout << "=== Defined Physical Step Length (DPSL)" << G4endl; + G4cout << " ++ProposedStep(UserLimit) = " << std::setw( 9) << physIntLength + << " : ProcName = User defined maximum allowed Step" << G4endl; + } +} +///////////////////////////////////////////// +void G4SteppingVerbose::DPSLPostStep() +///////////////////////////////////////////// +{ + if(Silent==1){ return; } + CopyState(); + + if( verboseLevel > 5 ){ + G4cout << " ++ProposedStep(PostStep ) = " << std::setw( 9) << physIntLength + << " : ProcName = " << fCurrentProcess->GetProcessName() << " ("; + if(fCondition==ExclusivelyForced){ + G4cout << "ExclusivelyForced)" << G4endl; + } + else if(fCondition==StronglyForced){ + G4cout << "StronglyForced)" << G4endl; + } + else if(fCondition==Conditionally){ + G4cout << "Conditionally)" << G4endl; + } + else if(fCondition==Forced){ + G4cout << "Forced)" << G4endl; + } + else{ + G4cout << "No ForceCondition)" << G4endl; + } + } +} +///////////////////////////////////////////// +void G4SteppingVerbose::DPSLAlongStep() +///////////////////////////////////////////// +{ + if(Silent==1){ return; } + CopyState(); + + if( verboseLevel > 5 ){ + G4cout << " ++ProposedStep(AlongStep) = " + << std::setw( 9) << G4BestUnit(physIntLength , "Length") + << " : ProcName = " + << fCurrentProcess->GetProcessName() + << " ("; + if(fGPILSelection==CandidateForSelection){ + G4cout << "CandidateForSelection)" << G4endl; + } + else if(fGPILSelection==NotCandidateForSelection){ + G4cout << "NotCandidateForSelection)" << G4endl; + } + else{ + G4cout << "?!?)" << G4endl; + } + } +} + + +//////////////////////////////////////////////// +void G4SteppingVerbose::TrackingStarted() +//////////////////////////////////////////////// +{ + if(Silent==1){ return; } + + CopyState(); + + G4int prec = G4cout.precision(3); + if( verboseLevel > 0 ){ + +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << std::setw( 5) << "Step#" << " " + << std::setw( 8) << "X" << " " + << std::setw( 8) << "Y" << " " + << std::setw( 8) << "Z" << " " + << std::setw( 9) << "KineE" << " " + << std::setw( 8) << "dE" << " " + << std::setw(12) << "StepLeng" << " " + << std::setw(12) << "TrackLeng" << " " + << std::setw(12) << "NextVolume" << " " + << std::setw( 8) << "ProcName" << G4endl; +#else + G4cout << std::setw( 5) << "Step#" << " " + << std::setw( 8) << "X(mm)" << " " + << std::setw( 8) << "Y(mm)" << " " + << std::setw( 8) << "Z(mm)" << " " + << std::setw( 9) << "KinE(MeV)" << " " + << std::setw( 8) << "dE(MeV)" << " " + << std::setw( 8) << "StepLeng" << " " + << std::setw( 9) << "TrackLeng" << " " + << std::setw(11) << "NextVolume" << " " + << std::setw( 8) << "ProcName" << G4endl; +#endif + + G4cout << std::setw( 5) << fTrack->GetCurrentStepNumber() << " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().x(),"Length")<< " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().y(),"Length") << " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().z(),"Length")<< " " + << std::setw( 9) << G4BestUnit(fTrack->GetKineticEnergy(),"Energy")<< " " + << std::setw( 8) << G4BestUnit(fStep->GetTotalEnergyDeposit(),"Energy") << " " + << std::setw( 8) << G4BestUnit(fStep->GetStepLength(),"Length")<< " " + << std::setw( 9) << G4BestUnit(fTrack->GetTrackLength(),"Length") << " "; + + if(fTrack->GetNextVolume()){ + G4cout << std::setw(11) << fTrack->GetNextVolume()->GetName() << " "; + } else { + G4cout << std::setw(11) << "OutOfWorld" << " "; + } + G4cout << "initStep" << G4endl; + } + G4cout.precision(prec); +} +////////////////////////////////////////////////////// +void G4SteppingVerbose::AlongStepDoItOneByOne() +////////////////////////////////////////////////////// +{ + if(Silent==1){ return; } + + CopyState(); + + if(verboseLevel >= 4){ + G4cout << G4endl; + G4cout << " >>AlongStepDoIt (process by process): " + << " Process Name = " + << fCurrentProcess->GetProcessName() << G4endl; + + ShowStep(); + G4cout << " " + << "!Note! Safety of PostStep is only valid " + << "after all DoIt invocations." + << G4endl; + + VerboseParticleChange(); + G4cout << G4endl; + + G4cout << " ++List of secondaries generated " + << "(x,y,z,kE,t,PID):" + << " No. of secodaries = " + << fN2ndariesAlongStepDoIt << G4endl; + + if(fN2ndariesAlongStepDoIt>0){ + for(size_t lp1=(*fSecondary).size()-fN2ndariesAlongStepDoIt; lp1<(*fSecondary).size(); lp1++){ + G4cout << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy() , "Energy")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetGlobalTime() , "Time")<< " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + } + } +} +////////////////////////////////////////////////////// +void G4SteppingVerbose::PostStepDoItOneByOne() +////////////////////////////////////////////////////// +{ + if(Silent==1){ return; } + + CopyState(); + + if(verboseLevel >= 4){ + G4cout << G4endl; + G4cout << " >>PostStepDoIt (process by process): " + << " Process Name = " + << fCurrentProcess->GetProcessName() << G4endl; + + ShowStep(); + G4cout << G4endl; + VerboseParticleChange(); + G4cout << G4endl; + + G4cout << " ++List of secondaries generated " + << "(x,y,z,kE,t,PID):" + << " No. of secodaries = " + << fN2ndariesPostStepDoIt << G4endl; + + if(fN2ndariesPostStepDoIt>0){ + for(size_t lp1=(*fSecondary).size()-fN2ndariesPostStepDoIt; lp1<(*fSecondary).size(); lp1++){ + G4cout << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y(), "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z(), "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy(), "Energy") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetGlobalTime(), "Time") << " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + } + } +} + + +////////////////////////////////////// +void G4SteppingVerbose::VerboseTrack() +////////////////////////////////////// +{ + if(Silent==1){ return; } + + CopyState(); +// Show header + G4cout << G4endl; + G4cout << " ++G4Track Information " << G4endl; + G4int prec = G4cout.precision(3); + + + G4cout << " -----------------------------------------------" + << G4endl; + G4cout << " G4Track Information " << std::setw(20) << G4endl; + G4cout << " -----------------------------------------------" + << G4endl; + + G4cout << " Step number : " + << std::setw(20) << fTrack->GetCurrentStepNumber() + << G4endl; +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << " Position - x : " + << std::setw(20) << G4BestUnit(fTrack->GetPosition().x(), "Length") + << G4endl; + G4cout << " Position - y : " + << std::setw(20) << G4BestUnit(fTrack->GetPosition().y(), "Length") + << G4endl; + G4cout << " Position - z : " + << std::setw(20) << G4BestUnit(fTrack->GetPosition().z(), "Length") + << G4endl; + G4cout << " Global Time : " + << std::setw(20) << G4BestUnit(fTrack->GetGlobalTime(), "Time") + << G4endl; + G4cout << " Local Time : " + << std::setw(20) << G4BestUnit(fTrack->GetLocalTime(), "Time") + << G4endl; +#else + G4cout << " Position - x (mm) : " + << std::setw(20) << fTrack->GetPosition().x() /mm + << G4endl; + G4cout << " Position - y (mm) : " + << std::setw(20) << fTrack->GetPosition().y() /mm + << G4endl; + G4cout << " Position - z (mm) : " + << std::setw(20) << fTrack->GetPosition().z() /mm + << G4endl; + G4cout << " Global Time (ns) : " + << std::setw(20) << fTrack->GetGlobalTime() /ns + << G4endl; + G4cout << " Local Time (ns) : " + << std::setw(20) << fTrack->GetLocalTime() /ns + << G4endl; +#endif + G4cout << " Momentum Direct - x : " + << std::setw(20) << fTrack->GetMomentumDirection().x() + << G4endl; + G4cout << " Momentum Direct - y : " + << std::setw(20) << fTrack->GetMomentumDirection().y() + << G4endl; + G4cout << " Momentum Direct - z : " + << std::setw(20) << fTrack->GetMomentumDirection().z() + << G4endl; +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << " Kinetic Energy : " +#else + G4cout << " Kinetic Energy (MeV): " +#endif + << std::setw(20) << G4BestUnit(fTrack->GetKineticEnergy(), "Energy") + << G4endl; + G4cout << " Polarization - x : " + << std::setw(20) << fTrack->GetPolarization().x() + << G4endl; + G4cout << " Polarization - y : " + << std::setw(20) << fTrack->GetPolarization().y() + << G4endl; + G4cout << " Polarization - z : " + << std::setw(20) << fTrack->GetPolarization().z() + << G4endl; + G4cout << " Track Length : " + << std::setw(20) << G4BestUnit(fTrack->GetTrackLength(), "Length") + << G4endl; + G4cout << " Track ID # : " + << std::setw(20) << fTrack->GetTrackID() + << G4endl; + G4cout << " Parent Track ID # : " + << std::setw(20) << fTrack->GetParentID() + << G4endl; + G4cout << " Next Volume : " + << std::setw(20); + if( fTrack->GetNextVolume() != 0 ) { + G4cout << fTrack->GetNextVolume()->GetName() << " "; + } else { + G4cout << "OutOfWorld" << " "; + } + G4cout << G4endl; + G4cout << " Track Status : " + << std::setw(20); + if( fTrack->GetTrackStatus() == fAlive ){ + G4cout << " Alive"; + } else if( fTrack->GetTrackStatus() == fStopButAlive ){ + G4cout << " StopButAlive"; + } else if( fTrack->GetTrackStatus() == fStopAndKill ){ + G4cout << " StopAndKill"; + } else if( fTrack->GetTrackStatus() == fKillTrackAndSecondaries ){ + G4cout << " KillTrackAndSecondaries"; + } else if( fTrack->GetTrackStatus() == fSuspend ){ + G4cout << " Suspend"; + } else if( fTrack->GetTrackStatus() == fPostponeToNextEvent ){ + G4cout << " PostponeToNextEvent"; + } + G4cout << G4endl; +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << " Vertex - x : " + << std::setw(20) << G4BestUnit(fTrack->GetVertexPosition().x(),"Length") + << G4endl; + G4cout << " Vertex - y : " + << std::setw(20) << G4BestUnit(fTrack->GetVertexPosition().y(),"Length") + << G4endl; + G4cout << " Vertex - z : " + << std::setw(20) << G4BestUnit(fTrack->GetVertexPosition().z(),"Length") + << G4endl; +#else + G4cout << " Vertex - x (mm) : " + << std::setw(20) << fTrack->GetVertexPosition().x()/mm + << G4endl; + G4cout << " Vertex - y (mm) : " + << std::setw(20) << fTrack->GetVertexPosition().y()/mm + << G4endl; + G4cout << " Vertex - z (mm) : " + << std::setw(20) << fTrack->GetVertexPosition().z()/mm + << G4endl; +#endif + G4cout << " Vertex - Px (MomDir): " + << std::setw(20) << fTrack->GetVertexMomentumDirection().x() + << G4endl; + G4cout << " Vertex - Py (MomDir): " + << std::setw(20) << fTrack->GetVertexMomentumDirection().y() + << G4endl; + G4cout << " Vertex - Pz (MomDir): " + << std::setw(20) << fTrack->GetVertexMomentumDirection().z() + << G4endl; +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << " Vertex - KineE : " +#else + G4cout << " Vertex - KineE (MeV): " +#endif + << std::setw(20) << G4BestUnit(fTrack->GetVertexKineticEnergy(),"Energy") + << G4endl; + + G4cout << " Creator Process : " + << std::setw(20); + if( fTrack->GetCreatorProcess() == 0){ + G4cout << " Event Generator" << G4endl; + } else { + G4cout << fTrack->GetCreatorProcess()->GetProcessName() << G4endl; + } + + G4cout << " -----------------------------------------------" + << G4endl; + + G4cout.precision(prec); +} + + +/////////////////////////////////////////////// +void G4SteppingVerbose::VerboseParticleChange() +/////////////////////////////////////////////// +{ + if(Silent==1){ return; } +// Show header + G4cout << G4endl; + G4cout << " ++G4ParticleChange Information " << G4endl; + fParticleChange->DumpInfo(); +} +///////////////////////////////////////// +void G4SteppingVerbose::ShowStep() const +//////////////////////////////////////// +{ + if(Silent==1){ return; } + G4String volName; + G4int oldprc; + +// Show header + G4cout << G4endl; + G4cout << " ++G4Step Information " << G4endl; + oldprc = G4cout.precision(16); + +// Show G4Step specific information + G4cout << " Address of G4Track : " << fStep->GetTrack() << G4endl; + G4cout << " Step Length (mm) : " << fStep->GetTrack()->GetStepLength() << G4endl; + G4cout << " Energy Deposit (MeV) : " << fStep->GetTotalEnergyDeposit() << G4endl; + +// Show G4StepPoint specific information + G4cout << " -------------------------------------------------------" + << "----------------" << G4endl; + G4cout << " StepPoint Information " << std::setw(20) << "PreStep" + << std::setw(20) << "PostStep" << G4endl; + G4cout << " -------------------------------------------------------" + << "----------------" << G4endl; + G4cout << " Position - x (mm) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPosition().x() + << std::setw(20) << fStep->GetPostStepPoint()->GetPosition().x() << G4endl; + G4cout << " Position - y (mm) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPosition().y() + << std::setw(20) << fStep->GetPostStepPoint()->GetPosition().y() << G4endl; + G4cout << " Position - z (mm) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPosition().z() + << std::setw(20) << fStep->GetPostStepPoint()->GetPosition().z() << G4endl; + G4cout << " Global Time (ns) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetGlobalTime() + << std::setw(20) << fStep->GetPostStepPoint()->GetGlobalTime() << G4endl; + G4cout << " Local Time (ns) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetLocalTime() + << std::setw(20) << fStep->GetPostStepPoint()->GetLocalTime() << G4endl; + G4cout << " Proper Time (ns) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetProperTime() + << std::setw(20) << fStep->GetPostStepPoint()->GetProperTime() << G4endl; + G4cout << " Momentum Direct - x : " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentumDirection().x() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentumDirection().x() << G4endl; + G4cout << " Momentum Direct - y : " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentumDirection().y() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentumDirection().y() << G4endl; + G4cout << " Momentum Direct - z : " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentumDirection().z() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentumDirection().z() << G4endl; + G4cout << " Momentum - x (MeV/c): " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentum().x() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentum().x() << G4endl; + G4cout << " Momentum - y (MeV/c): " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentum().y() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentum().y() << G4endl; + G4cout << " Momentum - z (MeV/c): " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentum().z() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentum().z() << G4endl; + G4cout << " Total Energy (MeV) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetTotalEnergy() + << std::setw(20) << fStep->GetPostStepPoint()->GetTotalEnergy() << G4endl; + G4cout << " Kinetic Energy (MeV): " + << std::setw(20) << fStep->GetPreStepPoint()->GetKineticEnergy() + << std::setw(20) << fStep->GetPostStepPoint()->GetKineticEnergy() << G4endl; + G4cout << " Velocity (mm/ns) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetVelocity() + << std::setw(20) << fStep->GetPostStepPoint()->GetVelocity() << G4endl; + G4cout << " Volume Name : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPhysicalVolume()->GetName(); + if (fStep->GetPostStepPoint()->GetPhysicalVolume()) + { + volName = fStep->GetPostStepPoint()->GetPhysicalVolume()->GetName(); + } + else + { + volName = "OutOfWorld"; + } + G4cout << std::setw(20) << volName << G4endl; + G4cout << " Safety (mm) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetSafety() + << std::setw(20) << fStep->GetPostStepPoint()->GetSafety() << G4endl; + G4cout << " Polarization - x : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPolarization().x() + << std::setw(20) << fStep->GetPostStepPoint()->GetPolarization().x() << G4endl; + G4cout << " Polarization - y : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPolarization().y() + << std::setw(20) << fStep->GetPostStepPoint()->GetPolarization().y() << G4endl; + G4cout << " Polarization - Z : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPolarization().z() + << std::setw(20) << fStep->GetPostStepPoint()->GetPolarization().z() << G4endl; + G4cout << " Weight : " + << std::setw(20) << fStep->GetPreStepPoint()->GetWeight() + << std::setw(20) << fStep->GetPostStepPoint()->GetWeight() << G4endl; + G4cout << " Step Status : " ; + G4StepStatus tStepStatus = fStep->GetPreStepPoint()->GetStepStatus(); + if( tStepStatus == fGeomBoundary ){ + G4cout << std::setw(20) << "Geom Limit"; + } else if ( tStepStatus == fAlongStepDoItProc ){ + G4cout << std::setw(20) << "AlongStep Proc."; + } else if ( tStepStatus == fPostStepDoItProc ){ + G4cout << std::setw(20) << "PostStep Proc"; + } else if ( tStepStatus == fAtRestDoItProc ){ + G4cout << std::setw(20) << "AtRest Proc"; + } else if ( tStepStatus == fUndefined ){ + G4cout << std::setw(20) << "Undefined"; + } + + tStepStatus = fStep->GetPostStepPoint()->GetStepStatus(); + if( tStepStatus == fGeomBoundary ){ + G4cout << std::setw(20) << "Geom Limit"; + } else if ( tStepStatus == fAlongStepDoItProc ){ + G4cout << std::setw(20) << "AlongStep Proc."; + } else if ( tStepStatus == fPostStepDoItProc ){ + G4cout << std::setw(20) << "PostStep Proc"; + } else if ( tStepStatus == fAtRestDoItProc ){ + G4cout << std::setw(20) << "AtRest Proc"; + } else if ( tStepStatus == fUndefined ){ + G4cout << std::setw(20) << "Undefined"; + } + + G4cout << G4endl; + G4cout << " Process defined Step: " ; + if( fStep->GetPreStepPoint()->GetProcessDefinedStep() == 0 ){ + G4cout << std::setw(20) << "Undefined"; + } else { + G4cout << std::setw(20) << fStep->GetPreStepPoint()->GetProcessDefinedStep()->GetProcessName(); + } + if( fStep->GetPostStepPoint()->GetProcessDefinedStep() == 0){ + G4cout << std::setw(20) << "Undefined"; + } else { + G4cout << std::setw(20) << fStep->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName(); + } + G4cout.precision(oldprc); + + G4cout << G4endl; + G4cout << " -------------------------------------------------------" + << "----------------" << G4endl; +} + + diff --git a/src/G4.10.02.p02fixes/G4Transportation.cc b/src/G4.10.02.p02fixes/G4Transportation.cc new file mode 100644 index 0000000..8b2a154 --- /dev/null +++ b/src/G4.10.02.p02fixes/G4Transportation.cc @@ -0,0 +1,827 @@ +// +// ******************************************************************** +// * 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: G4Transportation.cc 2011/06/10 16:19:46 japost Exp japost $ +// +// ------------------------------------------------------------ +// GEANT 4 include file implementation +// +// ------------------------------------------------------------ +// +// This class is a process responsible for the transportation of +// a particle, ie the geometrical propagation that encounters the +// geometrical sub-volumes of the detectors. +// +// It is also tasked with the key role of proposing the "isotropic safety", +// which will be used to update the post-step point's safety. +// +// ======================================================================= +// Modified: +// 10 Jan 2015, M.Kelsey: Use G4DynamicParticle mass, NOT PDGMass +// 28 Oct 2011, P.Gumpl./J.Ap: Detect gravity field, use magnetic moment +// 20 Nov 2008, J.Apostolakis: Push safety to helper - after ComputeSafety +// 9 Nov 2007, J.Apostolakis: Flag for short steps, push safety to helper +// 19 Jan 2006, P.MoraDeFreitas: Fix for suspended tracks (StartTracking) +// 11 Aug 2004, M.Asai: Add G4VSensitiveDetector* for updating stepPoint. +// 21 June 2003, J.Apostolakis: Calling field manager with +// track, to enable it to configure its accuracy +// 13 May 2003, J.Apostolakis: Zero field areas now taken into +// account correclty in all cases (thanks to W Pokorski). +// 29 June 2001, J.Apostolakis, D.Cote-Ahern, P.Gumplinger: +// correction for spin tracking +// 20 Febr 2001, J.Apostolakis: update for new FieldTrack +// 22 Sept 2000, V.Grichine: update of Kinetic Energy +// Created: 19 March 1997, J. Apostolakis +// ======================================================================= + +#include "G4Transportation.hh" +#include "G4TransportationProcessType.hh" + +#include "G4PhysicalConstants.hh" +#include "G4SystemOfUnits.hh" +#include "G4ProductionCutsTable.hh" +#include "G4ParticleTable.hh" + +#include "G4ChargeState.hh" +#include "G4EquationOfMotion.hh" + +#include "G4FieldManagerStore.hh" + +class G4VSensitiveDetector; + +G4bool G4Transportation::fUseMagneticMoment=false; + +// #define G4DEBUG_TRANSPORT 1 + +////////////////////////////////////////////////////////////////////////// +// +// Constructor + +G4Transportation::G4Transportation( G4int verbosity ) + : G4VProcess( G4String("Transportation"), fTransportation ), + fTransportEndPosition( 0.0, 0.0, 0.0 ), + fTransportEndMomentumDir( 0.0, 0.0, 0.0 ), + fTransportEndKineticEnergy( 0.0 ), + fTransportEndSpin( 0.0, 0.0, 0.0 ), + fMomentumChanged(true), + fEndGlobalTimeComputed(false), + fCandidateEndGlobalTime(0.0), + fParticleIsLooping( false ), + fNewTrack( true ), + fFirstStepInVolume( true ), + fLastStepInVolume( false ), + fGeometryLimitedStep(true), + fFieldExertedForce( false ), + fPreviousSftOrigin( 0.,0.,0. ), + fPreviousSafety( 0.0 ), + // fParticleChange(), + fEndPointDistance( -1.0 ), + fThreshold_Warning_Energy( 100 * MeV ), + fThreshold_Important_Energy( 250 * MeV ), + fThresholdTrials( 10 ), + fNoLooperTrials( 0 ), + fSumEnergyKilled( 0.0 ), fMaxEnergyKilled( 0.0 ), + fShortStepOptimisation( false ), // Old default: true (=fast short steps) + fVerboseLevel( verbosity ) +{ + // set Process Sub Type + SetProcessSubType(static_cast(TRANSPORTATION)); + pParticleChange= &fParticleChange; // Required to conform to G4VProcess + + G4TransportationManager* transportMgr ; + + transportMgr = G4TransportationManager::GetTransportationManager() ; + + fLinearNavigator = transportMgr->GetNavigatorForTracking() ; + + fFieldPropagator = transportMgr->GetPropagatorInField() ; + + fpSafetyHelper = transportMgr->GetSafetyHelper(); // New + + // Cannot determine whether a field exists here, as it would + // depend on the relative order of creating the detector's + // field and this process. That order is not guaranted. + // Instead later the method DoesGlobalFieldExist() is called + + static G4ThreadLocal G4TouchableHandle* pNullTouchableHandle = 0; + if ( !pNullTouchableHandle) { pNullTouchableHandle = new G4TouchableHandle; } + fCurrentTouchableHandle = *pNullTouchableHandle; + // Points to (G4VTouchable*) 0 + +#ifdef G4VERBOSE + if( fVerboseLevel > 0) + { + G4cout << " G4Transportation constructor> set fShortStepOptimisation to "; + if ( fShortStepOptimisation ) G4cout << "true" << G4endl; + else G4cout << "false" << G4endl; + } +#endif +} + +////////////////////////////////////////////////////////////////////////// + +G4Transportation::~G4Transportation() +{ + if( (fVerboseLevel > 0) && (fSumEnergyKilled > 0.0 ) ) + { + G4cout << " G4Transportation: Statistics for looping particles " << G4endl; + G4cout << " Sum of energy of loopers killed: " << fSumEnergyKilled << G4endl; + G4cout << " Max energy of loopers killed: " << fMaxEnergyKilled << G4endl; + } +} + +////////////////////////////////////////////////////////////////////////// +// +// Responsibilities: +// Find whether the geometry limits the Step, and to what length +// Calculate the new value of the safety and return it. +// Store the final time, position and momentum. + +G4double G4Transportation:: +AlongStepGetPhysicalInteractionLength( const G4Track& track, + G4double, // previousStepSize + G4double currentMinimumStep, + G4double& currentSafety, + G4GPILSelection* selection ) +{ + G4double geometryStepLength= -1.0, newSafety= -1.0; + fParticleIsLooping = false ; + + // Initial actions moved to StartTrack() + // -------------------------------------- + // Note: in case another process changes touchable handle + // it will be necessary to add here (for all steps) + // fCurrentTouchableHandle = aTrack->GetTouchableHandle(); + + // GPILSelection is set to defaule value of CandidateForSelection + // It is a return value + // + *selection = CandidateForSelection ; + + fFirstStepInVolume= fNewTrack || fLastStepInVolume; + // G4cout << " Transport::AlongStep GPIL: 1st-step= " << fFirstStepInVolume << " newTrack= " << fNewTrack << " fLastStep-in-Vol= " << fLastStepInVolume << G4endl; + fLastStepInVolume= false; + fNewTrack = false; + + fParticleChange.ProposeFirstStepInVolume(fFirstStepInVolume); + + // Get initial Energy/Momentum of the track + // + const G4DynamicParticle* pParticle = track.GetDynamicParticle() ; + const G4ParticleDefinition* pParticleDef = pParticle->GetDefinition() ; + G4ThreeVector startMomentumDir = pParticle->GetMomentumDirection() ; + G4ThreeVector startPosition = track.GetPosition() ; + + // G4double theTime = track.GetGlobalTime() ; + + // The Step Point safety can be limited by other geometries and/or the + // assumptions of any process - it's not always the geometrical safety. + // We calculate the starting point's isotropic safety here. + // + G4ThreeVector OriginShift = startPosition - fPreviousSftOrigin ; + G4double MagSqShift = OriginShift.mag2() ; + if( MagSqShift >= sqr(fPreviousSafety) ) + { + currentSafety = 0.0 ; + } + else + { + currentSafety = fPreviousSafety - std::sqrt(MagSqShift) ; + } + + // Is the particle charged or has it a magnetic moment? + // + G4double particleCharge = pParticle->GetCharge() ; + G4double magneticMoment = pParticle->GetMagneticMoment() ; + G4double restMass = pParticle->GetMass() ; + + fGeometryLimitedStep = false ; + // fEndGlobalTimeComputed = false ; + + // There is no need to locate the current volume. It is Done elsewhere: + // On track construction + // By the tracking, after all AlongStepDoIts, in "Relocation" + + // Check if the particle has a force, EM or gravitational, exerted on it + // + G4FieldManager* fieldMgr=0; + G4bool fieldExertsForce = false ; + + G4bool gravityOn = false; + G4bool fieldExists= false; // Field is not 0 (null pointer) + + fieldMgr = fFieldPropagator->FindAndSetFieldManager( track.GetVolume() ); + if( fieldMgr != 0 ) + { + // Message the field Manager, to configure it for this track + fieldMgr->ConfigureForTrack( &track ); + // Is here to allow a transition from no-field pointer + // to finite field (non-zero pointer). + + // If the field manager has no field ptr, the field is zero + // by definition ( = there is no field ! ) + const G4Field* ptrField= fieldMgr->GetDetectorField(); + fieldExists = (ptrField!=0) ; + if( fieldExists ) + { + gravityOn= ptrField->IsGravityActive(); + + if( (particleCharge != 0.0) + || (fUseMagneticMoment && (magneticMoment != 0.0) ) + || (gravityOn && (restMass != 0.0) ) + ) + { + fieldExertsForce = fieldExists; + } + } + } + // G4cout << " G4Transport: field exerts force= " << fieldExertsForce + // << " fieldMgr= " << fieldMgr << G4endl; + fFieldExertedForce = fieldExertsForce; + + if( !fieldExertsForce ) + { + G4double linearStepLength ; + if( fShortStepOptimisation && (currentMinimumStep <= currentSafety) ) + { + // The Step is guaranteed to be taken + // + geometryStepLength = currentMinimumStep ; + fGeometryLimitedStep = false ; + } + else + { + // Find whether the straight path intersects a volume + // + linearStepLength = fLinearNavigator->ComputeStep( startPosition, + startMomentumDir, + currentMinimumStep, + newSafety) ; + // Remember last safety origin & value. + // + fPreviousSftOrigin = startPosition ; + fPreviousSafety = newSafety ; + fpSafetyHelper->SetCurrentSafety( newSafety, startPosition); + + currentSafety = newSafety ; + + fGeometryLimitedStep= (linearStepLength <= currentMinimumStep); + if( fGeometryLimitedStep ) + { + // The geometry limits the Step size (an intersection was found.) + geometryStepLength = linearStepLength ; + } + else + { + // The full Step is taken. + geometryStepLength = currentMinimumStep ; + } + } + fEndPointDistance = geometryStepLength ; + + // Calculate final position + // + fTransportEndPosition = startPosition+geometryStepLength*startMomentumDir ; + + // Momentum direction, energy and polarisation are unchanged by transport + // + fTransportEndMomentumDir = startMomentumDir ; + fTransportEndKineticEnergy = track.GetKineticEnergy() ; + fTransportEndSpin = track.GetPolarization(); + fParticleIsLooping = false ; + fMomentumChanged = false ; + fEndGlobalTimeComputed = false ; + } + else // A field exerts force + { + G4double momentumMagnitude = pParticle->GetTotalMomentum() ; + G4ThreeVector EndUnitMomentum ; + G4double lengthAlongCurve ; + + G4ChargeState chargeState(particleCharge, // The charge can change (dynamic) + magneticMoment, + pParticleDef->GetPDGSpin() ); + // For insurance, could set it again + // chargeState.SetPDGSpin(pParticleDef->GetPDGSpin() ); // Provisionally in same object + + G4EquationOfMotion* equationOfMotion = + (fFieldPropagator->GetChordFinder()->GetIntegrationDriver()->GetStepper()) + ->GetEquationOfMotion(); + +// equationOfMotion->SetChargeMomentumMass( particleCharge, + equationOfMotion->SetChargeMomentumMass( chargeState, + momentumMagnitude, + restMass); + + G4FieldTrack aFieldTrack = G4FieldTrack( startPosition, + track.GetGlobalTime(), // Lab. + // track.GetProperTime(), // Particle rest frame + track.GetMomentumDirection(), + track.GetKineticEnergy(), + restMass, + particleCharge, + track.GetPolarization(), + pParticleDef->GetPDGMagneticMoment(), + 0.0, // Length along track + pParticleDef->GetPDGSpin() + ) ; + + if( currentMinimumStep > 0 ) + { + // Do the Transport in the field (non recti-linear) + // + lengthAlongCurve = fFieldPropagator->ComputeStep( aFieldTrack, + currentMinimumStep, + currentSafety, + track.GetVolume() ) ; + + fGeometryLimitedStep= fFieldPropagator->IsLastStepInVolume(); + // It is possible that step was reduced in PropagatorInField due to previous zero steps + // To cope with case that reduced step is taken in full, we must rely on PiF to obtain this + // value. + + geometryStepLength = std::min( lengthAlongCurve, currentMinimumStep ); + + // Remember last safety origin & value. + // + fPreviousSftOrigin = startPosition ; + fPreviousSafety = currentSafety ; + fpSafetyHelper->SetCurrentSafety( currentSafety, startPosition); + } + else + { + geometryStepLength = lengthAlongCurve= 0.0 ; + fGeometryLimitedStep = false ; + } + + // Get the End-Position and End-Momentum (Dir-ection) + // + fTransportEndPosition = aFieldTrack.GetPosition() ; + + // Momentum: Magnitude and direction can be changed too now ... + // + fMomentumChanged = true ; + fTransportEndMomentumDir = aFieldTrack.GetMomentumDir() ; + + fTransportEndKineticEnergy = aFieldTrack.GetKineticEnergy() ; + + if( fFieldPropagator->GetCurrentFieldManager()->DoesFieldChangeEnergy() ) + { + // If the field can change energy, then the time must be integrated + // - so this should have been updated + // + fCandidateEndGlobalTime = aFieldTrack.GetLabTimeOfFlight(); + fEndGlobalTimeComputed = true; + + // was ( fCandidateEndGlobalTime != track.GetGlobalTime() ); + // a cleaner way is to have FieldTrack knowing whether time is updated. + } + else + { + // The energy should be unchanged by field transport, + // - so the time changed will be calculated elsewhere + // + fEndGlobalTimeComputed = false; + + // Check that the integration preserved the energy + // - and if not correct this! + G4double startEnergy= track.GetKineticEnergy(); + G4double endEnergy= fTransportEndKineticEnergy; + + static G4ThreadLocal G4int no_inexact_steps=0, no_large_ediff; + G4double absEdiff = std::fabs(startEnergy- endEnergy); + if( absEdiff > perMillion * endEnergy ) + { + no_inexact_steps++; + // Possible statistics keeping here ... + } + if( fVerboseLevel > 1 ) + { + if( std::fabs(startEnergy- endEnergy) > perThousand * endEnergy ) + { + static G4ThreadLocal G4int no_warnings= 0, warnModulo=1, + moduloFactor= 10; + no_large_ediff ++; + if( (no_large_ediff% warnModulo) == 0 ) + { + no_warnings++; + G4cout << "WARNING - G4Transportation::AlongStepGetPIL() " + << " Energy change in Step is above 1^-3 relative value. " << G4endl + << " Relative change in 'tracking' step = " + << std::setw(15) << (endEnergy-startEnergy)/startEnergy << G4endl + << " Starting E= " << std::setw(12) << startEnergy / MeV << " MeV " << G4endl + << " Ending E= " << std::setw(12) << endEnergy / MeV << " MeV " << G4endl; + G4cout << " Energy has been corrected -- however, review" + << " field propagation parameters for accuracy." << G4endl; + if( (fVerboseLevel > 2 ) || (no_warnings<4) || (no_large_ediff == warnModulo * moduloFactor) ) + { + G4cout << " These include EpsilonStepMax(/Min) in G4FieldManager " + << " which determine fractional error per step for integrated quantities. " << G4endl + << " Note also the influence of the permitted number of integration steps." + << G4endl; + } + G4cerr << "ERROR - G4Transportation::AlongStepGetPIL()" << G4endl + << " Bad 'endpoint'. Energy change detected" + << " and corrected. " + << " Has occurred already " + << no_large_ediff << " times." << G4endl; + if( no_large_ediff == warnModulo * moduloFactor ) + { + warnModulo *= moduloFactor; + } + } + } + } // end of if (fVerboseLevel) + + // Correct the energy for fields that conserve it + // This - hides the integration error + // - but gives a better physical answer + fTransportEndKineticEnergy= track.GetKineticEnergy(); + } + + fTransportEndSpin = aFieldTrack.GetSpin(); + fParticleIsLooping = fFieldPropagator->IsParticleLooping() ; + fEndPointDistance = (fTransportEndPosition - startPosition).mag() ; + } + + // If we are asked to go a step length of 0, and we are on a boundary + // then a boundary will also limit the step -> we must flag this. + // + if( currentMinimumStep == 0.0 ) + { + if( currentSafety == 0.0 ) { fGeometryLimitedStep = true; } + } + + // Update the safety starting from the end-point, + // if it will become negative at the end-point. + // + if( currentSafety < fEndPointDistance ) + { + if( particleCharge != 0.0 ) + { + G4double endSafety = + fLinearNavigator->ComputeSafety( fTransportEndPosition) ; + currentSafety = endSafety ; + fPreviousSftOrigin = fTransportEndPosition ; + fPreviousSafety = currentSafety ; + fpSafetyHelper->SetCurrentSafety( currentSafety, fTransportEndPosition); + + // Because the Stepping Manager assumes it is from the start point, + // add the StepLength + // + currentSafety += fEndPointDistance ; + +#ifdef G4DEBUG_TRANSPORT + G4cout.precision(12) ; + G4cout << "***G4Transportation::AlongStepGPIL ** " << G4endl ; + G4cout << " Called Navigator->ComputeSafety at " << fTransportEndPosition + << " and it returned safety= " << endSafety << G4endl ; + G4cout << " Adding endpoint distance " << fEndPointDistance + << " to obtain pseudo-safety= " << currentSafety << G4endl ; + } + else + { + G4cout << "***G4Transportation::AlongStepGPIL ** " << G4endl ; + G4cout << " Avoiding call to ComputeSafety : " << G4endl; + G4cout << " charge = " << particleCharge << G4endl; + G4cout << " mag moment = " << magneticMoment << G4endl; +#endif + } + } + + fParticleChange.ProposeTrueStepLength(geometryStepLength) ; + + return geometryStepLength ; +} + +////////////////////////////////////////////////////////////////////////// +// +// Initialize ParticleChange (by setting all its members equal +// to corresponding members in G4Track) + +G4VParticleChange* G4Transportation::AlongStepDoIt( const G4Track& track, + const G4Step& stepData ) +{ + static G4ThreadLocal G4int noCalls=0; + noCalls++; + + fParticleChange.Initialize(track) ; + + // Code for specific process + // + fParticleChange.ProposePosition(fTransportEndPosition) ; + fParticleChange.ProposeMomentumDirection(fTransportEndMomentumDir) ; + fParticleChange.ProposeEnergy(fTransportEndKineticEnergy) ; + fParticleChange.SetMomentumChanged(fMomentumChanged) ; + + fParticleChange.ProposePolarization(fTransportEndSpin); + + G4double deltaTime = 0.0 ; + + // Calculate Lab Time of Flight (ONLY if field Equations used it!) + // G4double endTime = fCandidateEndGlobalTime; + // G4double delta_time = endTime - startTime; + + G4double startTime = track.GetGlobalTime() ; + + if (!fEndGlobalTimeComputed) + { + // The time was not integrated .. make the best estimate possible + // + G4double initialVelocity = stepData.GetPreStepPoint()->GetVelocity(); + G4double stepLength = track.GetStepLength(); + + deltaTime= 0.0; // in case initialVelocity = 0 + if ( initialVelocity > 0.0 ) { deltaTime = stepLength/initialVelocity; } + + fCandidateEndGlobalTime = startTime + deltaTime ; + fParticleChange.ProposeLocalTime( track.GetLocalTime() + deltaTime) ; + } + else + { + deltaTime = fCandidateEndGlobalTime - startTime ; + fParticleChange.ProposeGlobalTime( fCandidateEndGlobalTime ) ; + } + + + // Now Correct by Lorentz factor to get delta "proper" Time + + G4double restMass = track.GetDynamicParticle()->GetMass() ; + G4double deltaProperTime = deltaTime*( restMass/track.GetTotalEnergy() ) ; + + fParticleChange.ProposeProperTime(track.GetProperTime() + deltaProperTime) ; + //fParticleChange. ProposeTrueStepLength( track.GetStepLength() ) ; + + // If the particle is caught looping or is stuck (in very difficult + // boundaries) in a magnetic field (doing many steps) + // THEN this kills it ... + // + if ( fParticleIsLooping ) + { + G4double endEnergy= fTransportEndKineticEnergy; + + if( (endEnergy < fThreshold_Important_Energy) + || (fNoLooperTrials >= fThresholdTrials ) ) + { + // Kill the looping particle + // + fParticleChange.ProposeTrackStatus( fStopAndKill ) ; + + // 'Bare' statistics + fSumEnergyKilled += endEnergy; + if( endEnergy > fMaxEnergyKilled) { fMaxEnergyKilled= endEnergy; } + +#ifdef G4VERBOSE + if( (fVerboseLevel > 1) && + ( endEnergy > fThreshold_Warning_Energy ) ) + { + G4cout << " G4Transportation is killing track that is looping or stuck " + << G4endl + << " This track has " << track.GetKineticEnergy() / MeV + << " MeV energy." << G4endl; + G4cout << " Number of trials = " << fNoLooperTrials + << " No of calls to AlongStepDoIt = " << noCalls + << G4endl; + } +#endif + fNoLooperTrials=0; + } + else + { + fNoLooperTrials ++; +#ifdef G4VERBOSE + if( (fVerboseLevel > 2) ) + { + G4cout << " G4Transportation::AlongStepDoIt(): Particle looping - " + << " Number of trials = " << fNoLooperTrials + << " No of calls to = " << noCalls + << G4endl; + } +#endif + } + } + else + { + fNoLooperTrials=0; + } + + // Another (sometimes better way) is to use a user-limit maximum Step size + // to alleviate this problem .. + + // Introduce smooth curved trajectories to particle-change + // + fParticleChange.SetPointerToVectorOfAuxiliaryPoints + (fFieldPropagator->GimmeTrajectoryVectorAndForgetIt() ); + + return &fParticleChange ; +} + +////////////////////////////////////////////////////////////////////////// +// +// This ensures that the PostStep action is always called, +// so that it can do the relocation if it is needed. +// + +G4double G4Transportation:: +PostStepGetPhysicalInteractionLength( const G4Track&, + G4double, // previousStepSize + G4ForceCondition* pForceCond ) +{ + fFieldExertedForce = false; // Not known + *pForceCond = Forced ; + return DBL_MAX ; // was kInfinity ; but convention now is DBL_MAX +} + +///////////////////////////////////////////////////////////////////////////// +// + +G4VParticleChange* G4Transportation::PostStepDoIt( const G4Track& track, + const G4Step& ) +{ + G4TouchableHandle retCurrentTouchable ; // The one to return + G4bool isLastStep= false; + + // Initialize ParticleChange (by setting all its members equal + // to corresponding members in G4Track) + // fParticleChange.Initialize(track) ; // To initialise TouchableChange + + fParticleChange.ProposeTrackStatus(track.GetTrackStatus()) ; + + // If the Step was determined by the volume boundary, + // logically relocate the particle + + if(fGeometryLimitedStep) + { + // fCurrentTouchable will now become the previous touchable, + // and what was the previous will be freed. + // (Needed because the preStepPoint can point to the previous touchable) + + fLinearNavigator->SetGeometricallyLimitedStep() ; + fLinearNavigator-> + LocateGlobalPointAndUpdateTouchableHandle( track.GetPosition(), + track.GetMomentumDirection(), + fCurrentTouchableHandle, + true ) ; + // Check whether the particle is out of the world volume + // If so it has exited and must be killed. + // + if( fCurrentTouchableHandle->GetVolume() == 0 ) + { + fParticleChange.ProposeTrackStatus( fStopAndKill ) ; + } + retCurrentTouchable = fCurrentTouchableHandle ; + fParticleChange.SetTouchableHandle( fCurrentTouchableHandle ) ; + + // Update the Step flag which identifies the Last Step in a volume + if( !fFieldExertedForce ) + isLastStep = fLinearNavigator->ExitedMotherVolume() + | fLinearNavigator->EnteredDaughterVolume() ; + else + isLastStep = fFieldPropagator->IsLastStepInVolume(); + } + else // fGeometryLimitedStep is false + { + // This serves only to move the Navigator's location + // + fLinearNavigator->LocateGlobalPointWithinVolume( track.GetPosition() ) ; + + // The value of the track's current Touchable is retained. + // (and it must be correct because we must use it below to + // overwrite the (unset) one in particle change) + // It must be fCurrentTouchable too ?? + // + fParticleChange.SetTouchableHandle( track.GetTouchableHandle() ) ; + retCurrentTouchable = track.GetTouchableHandle() ; + + isLastStep= false; + } // endif ( fGeometryLimitedStep ) + fLastStepInVolume= isLastStep; + + fParticleChange.ProposeFirstStepInVolume(fFirstStepInVolume); + fParticleChange.ProposeLastStepInVolume(isLastStep); + + const G4VPhysicalVolume* pNewVol = retCurrentTouchable->GetVolume() ; + const G4Material* pNewMaterial = 0 ; + const G4VSensitiveDetector* pNewSensitiveDetector = 0 ; + + if( pNewVol != 0 ) + { + pNewMaterial= pNewVol->GetLogicalVolume()->GetMaterial(); + pNewSensitiveDetector= pNewVol->GetLogicalVolume()->GetSensitiveDetector(); + } + + // ( pNewMaterial ) ; + // ( pNewSensitiveDetector) ; + + fParticleChange.SetMaterialInTouchable( (G4Material *) pNewMaterial ) ; + fParticleChange.SetSensitiveDetectorInTouchable( (G4VSensitiveDetector *) pNewSensitiveDetector ) ; + + const G4MaterialCutsCouple* pNewMaterialCutsCouple = 0; + if( pNewVol != 0 ) + { + pNewMaterialCutsCouple=pNewVol->GetLogicalVolume()->GetMaterialCutsCouple(); + } + + if( pNewVol!=0 && pNewMaterialCutsCouple!=0 && pNewMaterialCutsCouple->GetMaterial()!=pNewMaterial ) + { + // for parametrized volume + // + pNewMaterialCutsCouple = + G4ProductionCutsTable::GetProductionCutsTable() + ->GetMaterialCutsCouple(pNewMaterial, + pNewMaterialCutsCouple->GetProductionCuts()); + } + fParticleChange.SetMaterialCutsCoupleInTouchable( pNewMaterialCutsCouple ); + + // temporarily until Get/Set Material of ParticleChange, + // and StepPoint can be made const. + // Set the touchable in ParticleChange + // this must always be done because the particle change always + // uses this value to overwrite the current touchable pointer. + // + fParticleChange.SetTouchableHandle(retCurrentTouchable) ; + + return &fParticleChange ; +} + +// New method takes over the responsibility to reset the state of G4Transportation +// object at the start of a new track or the resumption of a suspended track. + +void +G4Transportation::StartTracking(G4Track* aTrack) +{ + G4VProcess::StartTracking(aTrack); + fNewTrack= true; + fFirstStepInVolume= true; + fLastStepInVolume= false; + + // The actions here are those that were taken in AlongStepGPIL + // when track.GetCurrentStepNumber()==1 + + // reset safety value and center + // + fPreviousSafety = 0.0 ; + fPreviousSftOrigin = G4ThreeVector(0.,0.,0.) ; + + // reset looping counter -- for motion in field + fNoLooperTrials= 0; + // Must clear this state .. else it depends on last track's value + // --> a better solution would set this from state of suspended track TODO ? + // Was if( aTrack->GetCurrentStepNumber()==1 ) { .. } + + // ChordFinder reset internal state + // + if( fFieldPropagator ) + { + fFieldPropagator->ClearPropagatorState(); + // Resets all state of field propagator class (ONLY) + // including safety values (in case of overlaps and to wipe for first track). + + // G4ChordFinder* chordF= fFieldPropagator->GetChordFinder(); + // if( chordF ) chordF->ResetStepEstimate(); + } + + // Make sure to clear the chord finders of all fields (ie managers) + // + G4FieldManagerStore* fieldMgrStore = G4FieldManagerStore::GetInstance(); + fieldMgrStore->ClearAllChordFindersState(); + + // Update the current touchable handle (from the track's) + // + fCurrentTouchableHandle = aTrack->GetTouchableHandle(); + + // Inform field propagator of new track + fFieldPropagator->PrepareNewTrack(); +} + +#include "G4CoupledTransportation.hh" +G4bool G4Transportation::EnableUseMagneticMoment(G4bool useMoment) +{ + G4bool lastValue= fUseMagneticMoment; + fUseMagneticMoment= useMoment; + G4CoupledTransportation::fUseMagneticMoment= useMoment; + return lastValue; +} diff --git a/src/G4.10.03.p01fixes/G4IntersectingCone.cc b/src/G4.10.03.p01fixes/G4IntersectingCone.cc index 95be5c8..5acbc79 100644 --- a/src/G4.10.03.p01fixes/G4IntersectingCone.cc +++ b/src/G4.10.03.p01fixes/G4IntersectingCone.cc @@ -24,9 +24,8 @@ // ******************************************************************** // // -// $Id: G4IntersectingCone.cc 95997 2016-03-07 13:16:25Z gcosmo $ // -// +// // -------------------------------------------------------------------- // GEANT 4 class source file // @@ -45,45 +44,31 @@ // G4IntersectingCone::G4IntersectingCone( const G4double r[2], const G4double z[2] ) -{ +{ const G4double halfCarTolerance = 0.5 * G4GeometryTolerance::GetInstance()->GetSurfaceTolerance(); - // // What type of cone are we? // - type1 = (std::fabs(z[1]-z[0]) > std::fabs(r[1]-r[0])); - - if (type1) + type1 = (std::abs(z[1]-z[0]) > std::abs(r[1]-r[0])); + + if (type1) // tube like { - B = (r[1]-r[0])/(z[1]-z[0]); // tube like - A = 0.5*( r[1]+r[0] - B*(z[1]+z[0]) ); + B = (r[1] - r[0]) / (z[1] - z[0]); + A = (r[0]*z[1] - r[1]*z[0]) / (z[1] -z[0]); } - else + else // disk like { - B = (z[1]-z[0])/(r[1]-r[0]); // disk like - A = 0.5*( z[1]+z[0] - B*(r[1]+r[0]) ); + B = (z[1] - z[0]) / (r[1] - r[0]); + A = (z[0]*r[1] - z[1]*r[0]) / (r[1] - r[0]); } - // + // Calculate extent // - if (r[0] < r[1]) - { - rLo = r[0]-halfCarTolerance; rHi = r[1]+halfCarTolerance; - } - else - { - rLo = r[1]-halfCarTolerance; rHi = r[0]+halfCarTolerance; - } - - if (z[0] < z[1]) - { - zLo = z[0]-halfCarTolerance; zHi = z[1]+halfCarTolerance; - } - else - { - zLo = z[1]-halfCarTolerance; zHi = z[0]+halfCarTolerance; - } + rLo = std::min(r[0], r[1]) - halfCarTolerance; + rHi = std::max(r[0], r[1]) + halfCarTolerance; + zLo = std::min(z[0], z[1]) - halfCarTolerance; + zHi = std::max(z[0], z[1]) + halfCarTolerance; } @@ -172,11 +157,11 @@ G4int G4IntersectingCone::LineHitsCone( const G4ThreeVector &p, // // where: // -// a = x0**2 + y0**2 - (A + B*z0)**2 +// a = tx**2 + ty**2 - (B*tz)**2 // -// b = 2*( x0*tx + y0*ty - (A*B - B*B*z0)*tz) +// b = 2*( px*vx + py*vy - B*(A + B*pz)*vz ) // -// c = tx**2 + ty**2 - (B*tz)**2 +// c = x0**2 + y0**2 - (A + B*z0)**2 // // Notice, that if a < 0, this indicates that the two solutions (assuming // they exist) are in opposite cones (that is, given z0 = -A/B, one z < z0 @@ -192,7 +177,7 @@ G4int G4IntersectingCone::LineHitsCone( const G4ThreeVector &p, // This should be rare. // // For b*b - 4*a*c = 0, we also have one solution, which is almost always -// a line just grazing the surface of a the cone, which we want to ignore. +// a line just grazing the surface of a the cone, which we want to ignore. // However, there are two other, very rare, possibilities: // a line intersecting the z axis and either: // 1. At the same angle std::atan(B) to just miss one side of the cone, or @@ -205,12 +190,12 @@ G4int G4IntersectingCone::LineHitsCone( const G4ThreeVector &p, // // Now: x0*tx + y0*ty = 0 in terms of roundoff error. We can write: // Delta = x0*tx + y0*ty -// b = 2*( Delta - (A*B + B*B*z0)*tz ) +// b = 2*( Delta - B*(A + B*z0)*tz ) // For: // b*b - 4*a*c = epsilon // where epsilon is small, then: // Delta = epsilon/2/B -// +// G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, const G4ThreeVector &v, G4double *s1, G4double *s2 ) @@ -220,15 +205,35 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); G4double tx = v.x(), ty = v.y(), tz = v.z(); - G4double a = tx*tx + ty*ty - sqr(B*tz); - G4double b = 2*( x0*tx + y0*ty - (A*B + B*B*z0)*tz); - G4double c = x0*x0 + y0*y0 - sqr(A + B*z0); - - G4double radical = b*b - 4*a*c; - - if (radical < -EPS*EPS*b*b) { return 0; } // No solution - - if (radical < EPS*EPS*b*b) + // Value of radical can be inaccurate due to loss of precision + // if to calculate the coefficiets a,b,c like the following: + // G4double a = tx*tx + ty*ty - sqr(B*tz); + // G4double b = 2*( x0*tx + y0*ty - B*(A + B*z0)*tz); + // G4double c = x0*x0 + y0*y0 - sqr(A + B*z0); + // + // For more accurate calculation of radical the coefficients + // are splitted in two components, radial and along z-axis + // + G4double ar = tx*tx + ty*ty; + G4double az = sqr(B*tz); + G4double br = 2*(x0*tx + y0*ty); + G4double bz = 2*B*(A + B*z0)*tz; + G4double cr = x0*x0 + y0*y0; + G4double cz = sqr(A + B*z0); + + // Instead radical = b*b - 4*a*c + G4double arcz = 4*ar*cz; + G4double azcr = 4*az*cr; + G4double radical = (br*br - 4*ar*cr) + ((std::max(arcz,azcr) - 2*bz*br) + std::min(arcz,azcr)); + + // Find the coefficients + G4double a = ar - az; + G4double b = br - bz; + G4double c = cr - cz; + + if (radical < -EPS*std::fabs(b)) { return 0; } // No solution + + if (radical < EPS*std::fabs(b)) { // // The radical is roughly zero: check for special, very rare, cases @@ -236,7 +241,7 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, if (std::fabs(a) > 1/kInfinity) { if(B==0.) { return 0; } - if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/(B+1e-99)) ) + if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/B) ) { *s1 = -0.5*b/a; return 1; @@ -248,7 +253,7 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, { radical = std::sqrt(radical); } - + if (a > 1/kInfinity) { G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); @@ -278,7 +283,7 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, } } - + // // LineHitsCone2 // @@ -298,7 +303,7 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, // // a > 0 now means we intersect only once in the correct hemisphere. // -// a > 0 ? We only want solution which produces R > 0. +// a > 0 ? We only want solution which produces R > 0. // since R = (z0+s*tz-A)/B, for tz/B > 0, this is the largest s // for tz/B < 0, this is the smallest s // thus, same as in case 1 ( since sign(tz/B) = sign(tz*B) ) @@ -311,35 +316,55 @@ G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, // originally it was 1E-6 G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); G4double tx = v.x(), ty = v.y(), tz = v.z(); - + // Special case which might not be so rare: B = 0 (precisely) // if (B==0) { if (std::fabs(tz) < 1/kInfinity) { return 0; } - + *s1 = (A-z0)/tz; return 1; } + // Value of radical can be inaccurate due to loss of precision + // if to calculate the coefficiets a,b,c like the following: + // G4double a = tz*tz - B2*(tx*tx + ty*ty); + // G4double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) ); + // G4double c = sqr(z0-A) - B2*( x0*x0 + y0*y0 ); + // + // For more accurate calculation of radical the coefficients + // are splitted in two components, radial and along z-axis + // G4double B2 = B*B; - G4double a = tz*tz - B2*(tx*tx + ty*ty); - G4double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) ); - G4double c = sqr(z0-A) - B2*( x0*x0 + y0*y0 ); - - G4double radical = b*b - 4*a*c; - - if (radical < -EPS*EPS*b*b) { return 0; } // No solution - - if (radical < EPS*EPS*b*b) + G4double az = tz*tz; + G4double ar = B2*(tx*tx + ty*ty); + G4double bz = 2*(z0-A)*tz; + G4double br = 2*B2*(x0*tx + y0*ty); + G4double cz = sqr(z0-A); + G4double cr = B2*(x0*x0 + y0*y0); + + // Instead radical = b*b - 4*a*c + G4double arcz = 4*ar*cz; + G4double azcr = 4*az*cr; + G4double radical = (br*br - 4*ar*cr) + ((std::max(arcz,azcr) - 2*bz*br) + std::min(arcz,azcr)); + + // Find the coefficients + G4double a = az - ar; + G4double b = bz - br; + G4double c = cz - cr; + + if (radical < -EPS*std::fabs(b)) { return 0; } // No solution + + if (radical < EPS*std::fabs(b)) { // // The radical is roughly zero: check for special, very rare, cases // if (std::fabs(a) > 1/kInfinity) { - if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/(B+1e-99)) ) + if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/B) ) { *s1 = -0.5*b/a; return 1; @@ -351,7 +376,7 @@ G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, { radical = std::sqrt(radical); } - + if (a < -1/kInfinity) { G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); diff --git a/src/G4.10.03.p01fixes/G4IntersectingCone.cc-mine b/src/G4.10.03.p01fixes/G4IntersectingCone.cc-mine new file mode 100644 index 0000000..683efac --- /dev/null +++ b/src/G4.10.03.p01fixes/G4IntersectingCone.cc-mine @@ -0,0 +1,382 @@ +// +// ******************************************************************** +// * 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: G4IntersectingCone.cc 95997 2016-03-07 13:16:25Z gcosmo $ +// +// +// -------------------------------------------------------------------- +// GEANT 4 class source file +// +// +// G4IntersectingCone.cc +// +// Implementation of a utility class which calculates the intersection +// of an arbitrary line with a fixed cone +// -------------------------------------------------------------------- + +#include "G4IntersectingCone.hh" +#include "G4GeometryTolerance.hh" + +// +// Constructor +// +G4IntersectingCone::G4IntersectingCone( const G4double r[2], + const G4double z[2] ) +{ + const G4double halfCarTolerance + = 0.5 * G4GeometryTolerance::GetInstance()->GetSurfaceTolerance(); + + // + // What type of cone are we? + // + type1 = (std::fabs(z[1]-z[0]) > std::fabs(r[1]-r[0])); + + if (type1) + { + B = (r[1]-r[0])/(z[1]-z[0]); // tube like + A = 0.5*( r[1]+r[0] - B*(z[1]+z[0]) ); + } + else + { + B = (z[1]-z[0])/(r[1]-r[0]); // disk like + A = 0.5*( z[1]+z[0] - B*(r[1]+r[0]) ); + } + // + // Calculate extent + // + if (r[0] < r[1]) + { + rLo = r[0]-halfCarTolerance; rHi = r[1]+halfCarTolerance; + } + else + { + rLo = r[1]-halfCarTolerance; rHi = r[0]+halfCarTolerance; + } + + if (z[0] < z[1]) + { + zLo = z[0]-halfCarTolerance; zHi = z[1]+halfCarTolerance; + } + else + { + zLo = z[1]-halfCarTolerance; zHi = z[0]+halfCarTolerance; + } +} + + +// +// Fake default constructor - sets only member data and allocates memory +// for usage restricted to object persistency. +// +G4IntersectingCone::G4IntersectingCone( __void__& ) + : zLo(0.), zHi(0.), rLo(0.), rHi(0.), type1(false), A(0.), B(0.) +{ +} + + +// +// Destructor +// +G4IntersectingCone::~G4IntersectingCone() +{ +} + + +// +// HitOn +// +// Check r or z extent, as appropriate, to see if the point is possibly +// on the cone. +// +G4bool G4IntersectingCone::HitOn( const G4double r, + const G4double z ) +{ + // + // Be careful! The inequalities cannot be "<=" and ">=" here without + // punching a tiny hole in our shape! + // + if (type1) + { + if (z < zLo || z > zHi) return false; + } + else + { + if (r < rLo || r > rHi) return false; + } + + return true; +} + + +// +// LineHitsCone +// +// Calculate the intersection of a line with our conical surface, ignoring +// any phi division +// +G4int G4IntersectingCone::LineHitsCone( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + if (type1) + { + return LineHitsCone1( p, v, s1, s2 ); + } + else + { + return LineHitsCone2( p, v, s1, s2 ); + } +} + + +// +// LineHitsCone1 +// +// Calculate the intersections of a line with a conical surface. Only +// suitable if zPlane[0] != zPlane[1]. +// +// Equation of a line: +// +// x = x0 + s*tx y = y0 + s*ty z = z0 + s*tz +// +// Equation of a conical surface: +// +// x**2 + y**2 = (A + B*z)**2 +// +// Solution is quadratic: +// +// a*s**2 + b*s + c = 0 +// +// where: +// +// a = x0**2 + y0**2 - (A + B*z0)**2 +// +// b = 2*( x0*tx + y0*ty - (A*B - B*B*z0)*tz) +// +// c = tx**2 + ty**2 - (B*tz)**2 +// +// Notice, that if a < 0, this indicates that the two solutions (assuming +// they exist) are in opposite cones (that is, given z0 = -A/B, one z < z0 +// and the other z > z0). For our shapes, the invalid solution is one +// which produces A + Bz < 0, or the one where Bz is smallest (most negative). +// Since Bz = B*s*tz, if B*tz > 0, we want the largest s, otherwise, +// the smaller. +// +// If there are two solutions on one side of the cone, we want to make +// sure that they are on the "correct" side, that is A + B*z0 + s*B*tz >= 0. +// +// If a = 0, we have a linear problem: s = c/b, which again gives one solution. +// This should be rare. +// +// For b*b - 4*a*c = 0, we also have one solution, which is almost always +// a line just grazing the surface of a the cone, which we want to ignore. +// However, there are two other, very rare, possibilities: +// a line intersecting the z axis and either: +// 1. At the same angle std::atan(B) to just miss one side of the cone, or +// 2. Intersecting the cone apex (0,0,-A/B) +// We *don't* want to miss these! How do we identify them? Well, since +// this case is rare, we can at least swallow a little more CPU than we would +// normally be comfortable with. Intersection with the z axis means +// x0*ty - y0*tx = 0. Case (1) means a==0, and we've already dealt with that +// above. Case (2) means a < 0. +// +// Now: x0*tx + y0*ty = 0 in terms of roundoff error. We can write: +// Delta = x0*tx + y0*ty +// b = 2*( Delta - (A*B + B*B*z0)*tz ) +// For: +// b*b - 4*a*c = epsilon +// where epsilon is small, then: +// Delta = epsilon/2/B +// +G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + static const G4double EPS = DBL_EPSILON; // Precision constant, + // originally it was 1E-6 + G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); + G4double tx = v.x(), ty = v.y(), tz = v.z(); + + G4double a = tx*tx + ty*ty - sqr(B*tz); + G4double b = 2*( x0*tx + y0*ty - (A*B + B*B*z0)*tz); + G4double c = x0*x0 + y0*y0 - sqr(A + B*z0); + + G4double radical = b*b - 4*a*c; + + if (radical < -EPS*EPS*b*b) { return 0; } // No solution + + if (radical < EPS*EPS*b*b) + { + // + // The radical is roughly zero: check for special, very rare, cases + // + if (std::fabs(a) > 1/kInfinity) + { + //if(B==0.) { return 0; } + //if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/(B+1e-99)) ) + { + *s1 = -0.5*b/a; + return 1; + } + return 0; + } + } + else + { + radical = std::sqrt(radical); + } + + if (a > 1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + if (sa < sb) { *s1 = sa; *s2 = sb; } else { *s1 = sb; *s2 = sa; } + if (A + B*(z0+(*s1)*tz) < 0) { return 0; } + return 2; + } + else if (a < -1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + *s1 = (B*tz > 0)^(sa > sb) ? sb : sa; + return 1; + } + else if (std::fabs(b) < 1/kInfinity) + { + return 0; + } + else + { + *s1 = -c/b; + if (A + B*(z0+(*s1)*tz) < 0) { return 0; } + return 1; + } +} + + +// +// LineHitsCone2 +// +// See comments under LineHitsCone1. In this routine, case2, we have: +// +// Z = A + B*R +// +// The solution is still quadratic: +// +// a = tz**2 - B*B*(tx**2 + ty**2) +// +// b = 2*( (z0-A)*tz - B*B*(x0*tx+y0*ty) ) +// +// c = ( (z0-A)**2 - B*B*(x0**2 + y0**2) ) +// +// The rest is much the same, except some details. +// +// a > 0 now means we intersect only once in the correct hemisphere. +// +// a > 0 ? We only want solution which produces R > 0. +// since R = (z0+s*tz-A)/B, for tz/B > 0, this is the largest s +// for tz/B < 0, this is the smallest s +// thus, same as in case 1 ( since sign(tz/B) = sign(tz*B) ) +// +G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + static const G4double EPS = DBL_EPSILON; // Precision constant, + // originally it was 1E-6 + G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); + G4double tx = v.x(), ty = v.y(), tz = v.z(); + + // Special case which might not be so rare: B = 0 (precisely) + // + if (B==0) + { + if (std::fabs(tz) < 1/kInfinity) { return 0; } + + *s1 = (A-z0)/tz; + return 1; + } + + G4double B2 = B*B; + + G4double a = tz*tz - B2*(tx*tx + ty*ty); + G4double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) ); + G4double c = sqr(z0-A) - B2*( x0*x0 + y0*y0 ); + + G4double radical = b*b - 4*a*c; + + if (radical < -EPS*EPS*b*b) { return 0; } // No solution + + if (radical < EPS*EPS*b*b) + { + // + // The radical is roughly zero: check for special, very rare, cases + // + if (std::fabs(a) > 1/kInfinity) + { + //if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/(B+1e-99)) ) + { + *s1 = -0.5*b/a; + return 1; + } + return 0; + } + } + else + { + radical = std::sqrt(radical); + } + + if (a < -1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + if (sa < sb) { *s1 = sa; *s2 = sb; } else { *s1 = sb; *s2 = sa; } + if ((z0 + (*s1)*tz - A)/B < 0) { return 0; } + return 2; + } + else if (a > 1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + *s1 = (tz*B > 0)^(sa > sb) ? sb : sa; + return 1; + } + else if (std::fabs(b) < 1/kInfinity) + { + return 0; + } + else + { + *s1 = -c/b; + if ((z0 + (*s1)*tz - A)/B < 0) { return 0; } + return 1; + } +} diff --git a/src/G4.10.04.p02fixes/BooleanProcessor.src b/src/G4.10.04.p02fixes/BooleanProcessor.src new file mode 100644 index 0000000..649cbd8 --- /dev/null +++ b/src/G4.10.04.p02fixes/BooleanProcessor.src @@ -0,0 +1,2657 @@ +/*********************************************************************** + * * + * Name: BooleanProcessor Date: 10.12.99 * + * Author: E.Chernyaev Revised: * + * * + * Function: Internal class for executing boolean operations * + * on Polyhedra * + * * + ***********************************************************************/ + +//G.Barrand : begin +#define BP_GEANT4 + +#ifdef BP_GEANT4 //G.Barrand + +#include "G4Plane3D.hh" +#include "G4Point3D.hh" +#include "G4Normal3D.hh" +typedef G4Plane3D HVPlane3D; +typedef G4Point3D HVPoint3D; +typedef G4Normal3D HVNormal3D; + +#else //BP_HEPVIS + +#define ExtNode HEPVis_ExtNode +#define ExtEdge HEPVis_ExtEdge +#define ExtFace HEPVis_ExtFace +#define FaceList HEPVis_FaceList +#define ExtPolyhedron HEPVis_ExtPolyhedron +#define BooleanProcessor HEPVis_BooleanProcessor + +#define HepPolyhedron SbPolyhedron +#define G4Facet SbFacet + +#include +typedef HEPVis::SbPlane HVPlane3D; + +#endif + +//using namespace HepGeom; + +//#define BP_DEBUG + +//G.Barrand : end + +#define INITIAL_SIZE 200 +#define CRAZY_POINT HVPoint3D(-10.e+6, -10.e+6, -10.e+6) +//#define GRANULARITY 10.e+5; +//#define GRANULARITY 10.e+5 //G.Barrand : rm the trailing ; +#define GRANULARITY 1.e+9 //G.Barrand : rm the trailing ; + +#define SWAP(A,B) w = A; A = B; B = w + +#define OP_UNION 0 // Operations +#define OP_INTERSECTION 1 +#define OP_SUBTRACTION 2 + +#define OUT_OF_PLANE 0 // Face vs face statuses +#define ON_PLANE 1 +#define INTERSECTION 2 +#define EDGE 3 +#define NON_PLANAR_FACE 4 + +#define UNKNOWN_FACE 0 // Face statuses +#define ORIGINAL_FACE -1 +#define NEW_FACE -2 +#define UNSUITABLE_FACE -3 +#define DEFECTIVE_FACE -4 + +// -------------------------------------------- Simplified STL vector --- +//G.Barrand : begin +#include +using namespace std; +/* +template +class vector { + private: + int cur_size, max_size; + T * v; + + public: + vector(): cur_size(0), max_size(INITIAL_SIZE), v(new T[INITIAL_SIZE]) {} + ~vector() { delete [] v; } + + void clear() { cur_size = 0; } + int size() const { return cur_size; } + T & operator[](int i) { return v[i]; } + const T & operator[](int i) const { return v[i]; } + T & front() { return v[0]; } + const T & front() const { return v[0]; } + T & back() { return v[cur_size-1]; } + const T & back() const { return v[cur_size-1]; } + void pop_back() { cur_size--; } + void push_back(const T & a) { + if (cur_size == max_size) { + T * w = v; + max_size *= 2; + v = new T[max_size]; + for (int i=0; i& edges; //G.Barrand + public: + int iedges[4]; // indices of original edges + HVPlane3D plane; // face plane + double rmin[3], rmax[3]; // bounding box + int iold; // head of the list of the original edges + int inew; // head of the list of the new edges + int iprev; // index of previous face + int inext; // index of next face + + public: + //G.Barrand : ExtFace(int iedge=0) : iold(iedge), inew(0), iprev(iprev), inext(0) {} + ExtFace(std::vector& a_edges,int iedge) + : edges(a_edges), iold(iedge), inew(0), iprev(0), inext(0) { + //G.Barrand : initialize arrays to quiet valgrind. + {for (int i=0; i<4; i++) { iedges[i] = 0; }} + {for (int i=0; i<3; i++) { rmin[i] = 0; rmax[i] = 0; }} + } + ~ExtFace() {} + + ExtFace(const ExtFace & face) : + edges(face.edges), //G.Barrand + plane(face.plane), iold(face.iold), inew(face.inew), + iprev(face.iprev), inext(face.inext) + { + int i; + for (i=0; i<4; i++) { iedges[i] = face.iedges[i]; } + for (i=0; i<3; i++) { rmin[i] = face.rmin[i]; rmax[i] = face.rmax[i]; } + } + + ExtFace & operator=(const ExtFace & face) { + if (&face == this) return *this; + //FIXME : edges(face.edges) ???? //G.Barrand + int i; + for (i=0; i<4; i++) { iedges[i] = face.iedges[i]; } + plane = face.plane; + for (i=0; i<3; i++) { rmin[i] = face.rmin[i]; rmax[i] = face.rmax[i]; } + iold = face.iold; + inew = face.inew; + iprev = face.iprev; + inext = face.inext; + return *this; + } + + void invert(); +}; + +// ---------------------------------------------------- Global arrays --- +//G.Barrand : MacIntel : crash with g++-4.0.1 with -O on some subtract. +// Anyway static of objects is proved to be not safe. +// We put the below vector as members of BooleanProcessor. +//GB static std::vector nodes; // vector of nodes +//GB static std::vector edges; // vector of edges +//GB static std::vector faces; // vector of faces + +// ---------------------------------------------------- List of faces --- +class FaceList { + private: + std::vector& faces; //G.Barrad : end + private: + int ihead; + int ilast; + + public: + //G.Barrand : FaceList() : ihead(0), ilast(0) {} + FaceList(std::vector& a_faces) : faces(a_faces),ihead(0),ilast(0) {} + ~FaceList() {} + + void clean() { ihead = 0; ilast = 0; } + int front() { return ihead; } + + void push_back(int i) { + if (ilast == 0) { ihead = i; } else { faces[ilast].inext = i; } + ExtFace& face = faces[i]; //G.Barrand : optimize. + face.iprev = ilast; + face.inext = 0; + ilast = i; + } + + void remove(int i) { + ExtFace& face = faces[i]; //G.Barrand : optimize. + if (ihead == i) { + ihead = face.inext; + }else{ + faces[face.iprev].inext = face.inext; + } + if (ilast == i) { + ilast = face.iprev; + }else{ + faces[face.inext].iprev = face.iprev; + } + face.iprev = 0; + face.inext = 0; + } +}; + +// --------------------- Polyhedron with extended access to +// its members from the BooleanProcessor class --- +class ExtPolyhedron : public HepPolyhedron { + friend class BooleanProcessor; + virtual HepPolyhedron& operator = (const HepPolyhedron& from) { + return HepPolyhedron::operator = (from); + } +}; + +// ----------------------------------------- Boolean processor class --- +class BooleanProcessor { + private: + static G4ThreadLocal int ishift; //G.Barrand + std::vector nodes; // vector of nodes //G.Barrand + std::vector edges; // vector of edges //G.Barrand + std::vector faces; // vector of faces //G.Barrand + private: + int processor_error; // is set in case of error + int operation; // 0 (union), 1 (intersection), 2 (subtraction) + int ifaces1, ifaces2; // lists of faces + int iout1, iout2; // lists of faces with status "out" + int iunk1, iunk2; // lists of faces with status "unknown" + double rmin[3], rmax[3]; // intersection of bounding boxes + double del; // precision (tolerance) + + FaceList result_faces; // list of accepted faces + FaceList suitable_faces; // list of suitable faces + FaceList unsuitable_faces; // list of unsuitable faces + FaceList unknown_faces; // list of unknown faces + + vector external_contours; // heads of external contours + vector internal_contours; // heads of internal contours + + private: + void takePolyhedron(const HepPolyhedron & p, double, double, double); + double findMinMax(); + void selectOutsideFaces(int & ifaces, int & iout); + int testFaceVsPlane(ExtEdge & edge); + void renumberNodes(int & i1, int & i2, int & i3, int & i4); + int testEdgeVsEdge(ExtEdge & edge1, ExtEdge & edge2); + void removeJunkNodes() { while(nodes.back().s != 0) nodes.pop_back(); } + void divideEdge(int & i1, int & i2); + void insertEdge(const ExtEdge & edge); + void caseII(ExtEdge & edge1, ExtEdge & edge2); + void caseIE(ExtEdge & edge1, ExtEdge & edge2); + void caseEE(ExtEdge & edge1, ExtEdge & edge2); + void testFaceVsFace(int iface1, int iface2); + void invertNewEdges(int iface); + void checkDoubleEdges(int iface); + void assembleFace(int what, int iface); + void assembleNewFaces(int what, int ihead); + void initiateLists(); + void assemblePolyhedra(); + void findABC(double x1, double y1, double x2, double y2, + double &a, double &b, double &c) const; + int checkDirection(double *x, double *y) const; + int checkIntersection(int ix, int iy, int i1, int i2) const; + void mergeContours(int ix, int iy, int kext, int kint); + int checkTriangle(int iedge1, int iedge2, int ix, int iy) const; + void triangulateContour(int ix, int iy, int ihead); + void modifyReference(int iface, int i1, int i2, int iref); + void triangulateFace(int iface); + HepPolyhedron createPolyhedron(); + bool isInside(HVPoint3D &point, FaceList &poly); + void dump(FaceList &poly); + + public: + //G.Barrand : BooleanProcessor() {} + BooleanProcessor() //G.Barrand + :processor_error(0) // The next few fields are work space, initialised + ,operation(0) // here to prevent Coverity warnings. + ,ifaces1(0) // " + ,ifaces2(0) // " + ,iout1(0) // " + ,iout2(0) // " + ,iunk1(0) // " + ,iunk2(0) // " + ,del(0.) // " + ,result_faces(faces) + ,suitable_faces(faces) + ,unsuitable_faces(faces) + ,unknown_faces(faces) + { // rmin, rmax also initialised here to prevent Coverity warnings. + for (int i = 0; i < 3; i++) { + rmin[i] = 0.; + rmax[i] = 0.; + } + } + + ~BooleanProcessor() {} + + HepPolyhedron execute(int op, + const HepPolyhedron &a, + const HepPolyhedron &b, + int& err); + + void draw(); + void draw_edge(int, int); + void draw_contour(int, int, int); + void draw_faces(int, int, int); + void print_face(int); + void print_edge(int); + int get_processor_error() const {return processor_error;} + + void dump(); //G.Barrand + static int get_shift(); //G.Barrand + static void set_shift(int a_shift); //G.Barrand + static int get_num_shift(); //G.Barrand +}; + +inline void ExtFace::invert() +/*********************************************************************** + * * + * Name: ExtFace::invert() Date: 28.02.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Invert face * + * * + ***********************************************************************/ +{ + int iEprev, iEcur, iEnext; + + iEprev = 0; iEcur = iold; + while (iEcur > 0) { + ExtEdge& edge = edges[iEcur]; //G.Barrand : optimize. + edge.invert(); + iEnext = edge.inext; + edge.inext = iEprev; + iEprev = iEcur; + iEcur = iEnext; + } + if (iold > 0) iold = iEprev; + + iEprev = 0; iEcur = inew; + while (iEcur > 0) { + ExtEdge& edge = edges[iEcur]; //G.Barrand : optimize. + edge.invert(); + iEnext = edge.inext; + edge.inext = iEprev; + iEprev = iEcur; + iEcur = iEnext; + } + if (inew > 0) inew = iEprev; + +#ifdef BP_GEANT4 //G.Barrand + plane = HVPlane3D(-plane.a(), -plane.b(), -plane.c(), -plane.d()); +#else + plane = HVPlane3D(-plane.getNormal(), -plane.getDistanceFromOrigin()); +#endif +} + +void BooleanProcessor::takePolyhedron(const HepPolyhedron & p, + double dx, double dy, double dz) +/*********************************************************************** + * * + * Name: BooleanProcessor::takePolyhedron Date: 16.12.99 * + * Author: E.Chernyaev Revised: * + * * + * Function: Transfer Polyhedron to internal representation * + * * + ***********************************************************************/ +{ + int i = 0, k = 0, nnode = 0, iNodes[5] = {0,0,0,0,0}, iVis[4] = {0,0,0,0}, + iFaces[4] = {0,0,0,0}; + int dnode = nodes.size() - 1; + int dface = faces.size() - 1; + + // S E T N O D E S + + // for (i=1; i <= p.GetNoVertices(); i++) { + // nodes.push_back(ExtNode(p.GetVertex(i))); + // } + + HVPoint3D ppp; + for (i=1; i <= p.GetNoVertices(); i++) { +#ifdef BP_GEANT4 //G.Barrand + ppp = p.GetVertex(i); + ppp.setX(ppp.x()+dx); + ppp.setY(ppp.y()+dy); + ppp.setZ(ppp.z()+dz); +#else + ppp = p.GetVertexFast(i); + ppp += HVPoint3D(dx,dy,dz); +#endif + nodes.push_back(ExtNode(ppp)); + } + + // S E T F A C E S + + for (int iface=1; iface <= p.GetNoFacets(); iface++) { + faces.push_back(ExtFace(edges,edges.size())); + + // S E T F A C E N O D E S + + p.GetFacet(iface, nnode, iNodes, iVis, iFaces); + for (i=0; i p.GetNoVertices()) processor_error = 1; + //if (iFaces[i] < 1 || iFaces[i] > p.GetNoFacets()) processor_error = 1; + + if (iNodes[i] < 1 || iNodes[i] > p.GetNoVertices()) { //G.Barrand + processor_error = 1; +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::takePolyhedron : problem 1." + << G4endl; +#endif + } + if (iFaces[i] < 1 || iFaces[i] > p.GetNoFacets()) { //G.Barrand + processor_error = 1; +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::takePolyhedron : problem 2." + << G4endl; +#endif + } + iNodes[i] += dnode; + iFaces[i] += dface; + } + + // S E T E D G E S + + iNodes[nnode] = iNodes[0]; + faces.back().iedges[3] = 0; + for (i=0; i node.v[k]) + face.rmin[k] = node.v[k]; + if (face.rmax[k] < node.v[k]) + face.rmax[k] = node.v[k]; + } + } + + // S E T F A C E P L A N E + + HVNormal3D n = (nodes[iNodes[2]].v-nodes[iNodes[0]].v).cross + (nodes[iNodes[3]].v-nodes[iNodes[1]].v); + HVPoint3D point(0,0,0); + + for (i=0; i 1) point *= (1./nnode); + //G.Barrand : faces.back().plane = HVPlane3D(n.unit(), point); + //faces.back().plane = HVPlane3D(n, point); //G.Barrand + faces.back().plane = HVPlane3D(n.unit(), point); + + // S E T R E F E R E N C E T O T H E N E X T F A C E + + faces.back().inext = faces.size(); + } + faces.back().inext = 0; +} + +double BooleanProcessor::findMinMax() +/*********************************************************************** + * * + * Name: BooleanProcessor::findMinMax Date: 16.12.99 * + * Author: E.Chernyaev Revised: * + * * + * Function: Find min-max (bounding) boxes for polyhedra * + * * + ***********************************************************************/ +{ + if (ifaces1 == 0 || ifaces2 == 0) return 0; + + int i, iface; + double rmin1[3], rmax1[3]; + double rmin2[3], rmax2[3]; + + // F I N D B O U N D I N G B O X E S + + for (i=0; i<3; i++) { + rmin1[i] = faces[ifaces1].rmin[i]; + rmax1[i] = faces[ifaces1].rmax[i]; + rmin2[i] = faces[ifaces2].rmin[i]; + rmax2[i] = faces[ifaces2].rmax[i]; + } + + iface = faces[ifaces1].inext; + while(iface > 0) { + ExtFace& face = faces[iface]; //G.Barrand + for (i=0; i<3; i++) { + if (rmin1[i] > face.rmin[i]) rmin1[i] = face.rmin[i]; + if (rmax1[i] < face.rmax[i]) rmax1[i] = face.rmax[i]; + } + iface = face.inext; + } + + iface = faces[ifaces2].inext; + while(iface > 0) { + ExtFace& face = faces[iface]; //G.Barrand + for (i=0; i<3; i++) { + if (rmin2[i] > face.rmin[i]) rmin2[i] = face.rmin[i]; + if (rmax2[i] < face.rmax[i]) rmax2[i] = face.rmax[i]; + } + iface = face.inext; + } + + // F I N D I N T E R S E C T I O N O F B O U N D I N G B O X E S + + for (i=0; i<3; i++) { + rmin[i] = (rmin1[i] > rmin2[i]) ? rmin1[i] : rmin2[i]; + rmax[i] = (rmax1[i] < rmax2[i]) ? rmax1[i] : rmax2[i]; + } + + // F I N D T O L E R A N C E + + double del1 = 0; + double del2 = 0; + for (i=0; i<3; i++) { + if ((rmax1[i]-rmin1[i]) > del1) del1 = rmax1[i]-rmin1[i]; + if ((rmax2[i]-rmin2[i]) > del2) del2 = rmax2[i]-rmin2[i]; + } + return ((del1 < del2) ? del1 : del2) / GRANULARITY; +} + +void BooleanProcessor::selectOutsideFaces(int & ifaces, int & iout) +/*********************************************************************** + * * + * Name: BooleanProcessor::selectOutsideFaces Date: 10.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Preselection of outside faces * + * * + ***********************************************************************/ +{ + int i, outflag, iface = ifaces, *prev; + HVPoint3D mmbox[8] = { HVPoint3D(rmin[0],rmin[1],rmin[2]), + HVPoint3D(rmax[0],rmin[1],rmin[2]), + HVPoint3D(rmin[0],rmax[1],rmin[2]), + HVPoint3D(rmax[0],rmax[1],rmin[2]), + HVPoint3D(rmin[0],rmin[1],rmax[2]), + HVPoint3D(rmax[0],rmin[1],rmax[2]), + HVPoint3D(rmin[0],rmax[1],rmax[2]), + HVPoint3D(rmax[0],rmax[1],rmax[2]) }; + prev = &ifaces; + while (iface > 0) { + + // B O U N D I N G B O X vs B O U N D I N G B O X + + outflag = 0; + ExtFace& face = faces[iface]; //G.Barrand : optimize. + for (i=0; i<3; i++) { + if (face.rmin[i] > rmax[i] + del) { outflag = 1; break; } + if (face.rmax[i] < rmin[i] - del) { outflag = 1; break; } + } + + // B O U N D I N G B O X vs P L A N E + + if (outflag == 0) { + int npos = 0, nneg = 0; + double d; + for (i=0; i<8; i++) { + d = face.plane.distance(mmbox[i]); //G.Barrand : optimize + if (d > +del) npos++; + if (d < -del) nneg++; + } + if (npos == 8 || nneg == 8) outflag = 1; + } + + // U P D A T E L I S T S + + if (outflag == 1) { + *prev = face.inext; + face.inext = iout; + iout = iface; + }else{ + prev = &face.inext; + } + + iface = *prev; + } +} + +int BooleanProcessor::testFaceVsPlane(ExtEdge & edge) +/*********************************************************************** + * * + * Name: BooleanProcessor::testFaceVsPlane Date: 19.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Find result of intersection of face by plane * + * * + ***********************************************************************/ +{ + int iface = edge.iface1; + HVPlane3D plane = faces[edge.iface2].plane; + int i, nnode, npos = 0, nneg = 0, nzer = 0; + double dd[5]; + + // F I N D D I S T A N C E S + + nnode = (faces[iface].iedges[3] == 0) ? 3 : 4; + for (i=0; i del) { + npos++; + }else if (dd[i] < -del) { + nneg++; + }else{ + nzer++; dd[i] = 0; + } + } + + // S O M E S I M P L E C A S E S ( N O I N T E R S E C T I O N ) + + if (npos == nnode || nneg == nnode) return OUT_OF_PLANE; + if (nzer == 1 && nneg == 0) return OUT_OF_PLANE; + if (nzer == 1 && npos == 0) return OUT_OF_PLANE; + if (nzer == nnode) return ON_PLANE; + if (nzer == 3) return NON_PLANAR_FACE; + + // F I N D I N T E R S E C T I O N + + int ie1 = 0, ie2 = 0, s1 = 0, s2 = 0, status, nint = 0; + enum { PLUS_MINUS, MINUS_PLUS, ZERO_ZERO, ZERO_PLUS, ZERO_MINUS }; + + dd[nnode] = dd[0]; + for (i=0; i 0) { + if (dd[i+1] >= 0) continue; + status = PLUS_MINUS; + }else if (dd[i] < 0) { + if (dd[i+1] <= 0) continue; + status = MINUS_PLUS; + }else{ + status = ZERO_ZERO; + if (dd[i+1] > 0) status = ZERO_PLUS; + if (dd[i+1] < 0) status = ZERO_MINUS; + } + switch (nint) { + case 0: + ie1 = i; s1 = status; nint++; break; + case 1: + ie2 = i; s2 = status; nint++; break; + default: + return NON_PLANAR_FACE; + } + } + if (nint != 2) return NON_PLANAR_FACE; + + // F O R M I N T E R S E C T I O N S E G M E N T + + if (s1 != ZERO_ZERO && s2 != ZERO_ZERO) { + if (s1 == s2) return NON_PLANAR_FACE; + int iedge, i1 = 0, i2 = 0, ii[2]; + double d1 = 0., d2 = 0., d3 = 0.; + ii[0] = ie1; ii[1] = ie2; + for (i=0; i<2; i++) { + iedge = faces[iface].iedges[ii[i]]; + while (iedge > 0) { + i1 = edges[iedge].i1; + i2 = edges[iedge].i2; + + d1 = plane.distance(nodes[i1].v); + d2 = plane.distance(nodes[i2].v); + if (d1 > del) { + if (d2 < -del) { ii[i] = nodes.size(); break; } // +- + }else if (d1 < -del) { + if (d2 > del) { ii[i] = nodes.size(); break; } // -+ + }else{ + ii[i] = i1; break; // 0+ or 0- + } + iedge = edges[iedge].inext; + } + if (ii[i] == (int)nodes.size()) { + d3 = d2-d1; d1 = d1/d3; d2 = d2/d3; + nodes.push_back(ExtNode(d2*nodes[i1].v-d1*nodes[i2].v, iedge)); + } + } + edge.inext = 0; + if (s1 == MINUS_PLUS || s1 == ZERO_PLUS) { + edge.i1 = ii[1]; + edge.i2 = ii[0]; + }else{ + edge.i1 = ii[0]; + edge.i2 = ii[1]; + } + return INTERSECTION; + }else{ + if (npos == nneg) return NON_PLANAR_FACE; + edge.inext = (s1 == ZERO_ZERO) ? ie1+1 : ie2+1; + if (s1 == ZERO_PLUS || s2 == ZERO_MINUS) { + edge.i1 = edges[faces[iface].iedges[ie2]].i1; + edge.i2 = edges[faces[iface].iedges[ie1]].i1; + }else{ + edge.i1 = edges[faces[iface].iedges[ie1]].i1; + edge.i2 = edges[faces[iface].iedges[ie2]].i1; + } + return EDGE; + } +} + +void BooleanProcessor::renumberNodes(int & i1, int & i2, int & i3, int & i4) +/*********************************************************************** + * * + * Name: BooleanProcessor::renumberNodes Date: 19.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Renumber nodes and remove last temporary node. * + * Remark: In principal this routine can be replaced just * + * with i1 = i2; * + * Removal of temporary nodes provides additional control * + * on number of nodes, that is very useful for debugging. * + * * + ***********************************************************************/ +{ + if (i1 == i2) return; + if (nodes[i1].s == 0 || nodes.back().s == 0) { i1 = i2; return; } + + int ilast = nodes.size()-1; + if (i1 == ilast) { i1 = i2; nodes.pop_back(); return; } + if (i2 == ilast) { i2 = i1; } + if (i3 == ilast) { i3 = i1; } + if (i4 == ilast) { i4 = i1; } + nodes[i1] = nodes.back(); i1 = i2; nodes.pop_back(); +} + +int BooleanProcessor::testEdgeVsEdge(ExtEdge & edge1, ExtEdge & edge2) +/*********************************************************************** + * * + * Name: BooleanProcessor::testEdgeVsEdge Date: 19.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Find common part of two edges * + * * + ***********************************************************************/ +{ + int i, ii = 0; + double d, dd = 0.; + + for (i=0; i<3; i++) { + d = nodes[edge1.i1].v[i]-nodes[edge1.i2].v[i]; + if (d < 0.) d = -d; + if (d > dd) { dd = d; ii = i; } + } + double t1 = nodes[edge1.i1].v[ii]; + double t2 = nodes[edge1.i2].v[ii]; + double t3 = nodes[edge2.i1].v[ii]; + double t4 = nodes[edge2.i2].v[ii]; + if (t2-t1 < 0.) { t1 = -t1; t2 = -t2; t3 = -t3; t4 = -t4; } + + if (t3 <= t1+del || t4 >= t2-del) return 0; + if (t3 > t2+del) { + renumberNodes(edge2.i1, edge1.i2, edge1.i1, edge2.i2); + }else if (t3 < t2-del) { + renumberNodes(edge1.i2, edge2.i1, edge1.i1, edge2.i2); + } + if (t4 < t1-del) { + renumberNodes(edge2.i2, edge1.i1, edge1.i2, edge2.i1); + }else if (t4 > t1+del) { + renumberNodes(edge1.i1, edge2.i2, edge1.i2, edge2.i1); + } + return 1; +} + +void BooleanProcessor::divideEdge(int & i1, int & i2) +/*********************************************************************** + * * + * Name: BooleanProcessor::divideEdge Date: 24.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Unify the nodes and divide edge on two parts by the node. * + * * + ***********************************************************************/ +{ + int iedges[2]; + iedges[0] = nodes[i1].s; + iedges[1] = nodes[i2].s; + + // U N I F Y N O D E S + + if (i1 < i2) { i2 = i1; } + else if (i1 > i2) { i1 = i2; } + else { iedges[1] = 0; } + if (iedges[0] == iedges[1]) return; + + int ie1, ie2, inode = i1; + nodes[inode].s = 0; + for (int i=0; i<2; i++) { + + // F I N D C O R R E S P O N D I N G E D G E + + if ((ie1 = iedges[i]) == 0) continue; + ie2 = faces[edges[ie1].iface2].iedges[0]; + while (ie2 > 0) { + if (edges[ie2].i1 == edges[ie1].i2 && + edges[ie2].i2 == edges[ie1].i1) break; + ie2 = edges[ie2].inext; + } + + // D I V I D E E D G E S + + edges.push_back(edges[ie1]); + edges[ie1].inext = edges.size() - 1; + edges[ie1].i2 = inode; + edges.back().i1 = inode; + + edges.push_back(edges[ie2]); + edges[ie2].inext = edges.size() - 1; + edges[ie2].i2 = inode; + edges.back().i1 = inode; + } +} + +void BooleanProcessor::insertEdge(const ExtEdge & edge) +/*********************************************************************** + * * + * Name: BooleanProcessor::insertEdge Date: 24.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Insert edge to the list of new edges * + * * + ***********************************************************************/ +{ + int iface = edge.iface1; + edges.push_back(edge); + edges.back().inext = faces[iface].inew; + faces[iface].inew = edges.size() - 1; +} + +void BooleanProcessor::caseII(ExtEdge & edge1, ExtEdge & edge2) +/*********************************************************************** + * * + * Name: BooleanProcessor::caseII Date: 19.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Intersection/Intersection case * + * * + ***********************************************************************/ +{ + divideEdge(edge1.i1, edge2.i2); + divideEdge(edge1.i2, edge2.i1); + edge1.ivis = 1; + edge2.ivis = 1; + insertEdge(edge1); + insertEdge(edge2); +} + +void BooleanProcessor::caseIE(ExtEdge &, ExtEdge &) +/*********************************************************************** + * * + * Name: BooleanProcessor::caseIE Date: 19.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Intersection/Edge-touch case * + * * + ***********************************************************************/ +{ + processor_error = 1; +#ifdef BP_DEBUG + G4cout + << "BooleanProcessor::caseIE : unimplemented case" + << G4endl; +#endif +} + +void BooleanProcessor::caseEE(ExtEdge &, ExtEdge &) +/*********************************************************************** + * * + * Name: BooleanProcessor::caseEE Date: 19.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Edge-touch/Edge-touch case * + * * + ***********************************************************************/ +{ + processor_error = 1; +#ifdef BP_DEBUG + G4cout + << "BooleanProcessor::caseEE : unimplemented case" + << G4endl; +#endif +} + +void BooleanProcessor::testFaceVsFace(int iface1, int iface2) +/*********************************************************************** + * * + * Name: BooleanProcessor::testFaceVsFace Date: 11.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Find result (an edge) of intersection of two faces * + * * + ***********************************************************************/ +{ + ExtEdge edge1, edge2; + int irep1, irep2; + + // M I N - M A X + + {const ExtFace& face_1 = faces[iface1]; //G.Barrand : optimize + const ExtFace& face_2 = faces[iface2]; + for (int i=0; i<3; i++) { + if (face_1.rmin[i] > face_2.rmax[i] + del) return; + if (face_1.rmax[i] < face_2.rmin[i] - del) return; + }} + + // F A C E - 1 vs P L A N E - 2 + + edge1.iface1 = iface1; + edge1.iface2 = iface2; + irep1 = testFaceVsPlane(edge1); + if (irep1 == OUT_OF_PLANE || irep1 == ON_PLANE) { + removeJunkNodes(); + return; + } + + // F A C E - 2 vs P L A N E - 1 + + edge2.iface1 = iface2; + edge2.iface2 = iface1; + irep2 = testFaceVsPlane(edge2); + if (irep2 == OUT_OF_PLANE || irep2 == ON_PLANE) { + removeJunkNodes(); + return; + } + + // C H E C K F O R N O N P L A N A R F A C E + + if (irep1 == NON_PLANAR_FACE || irep2 == NON_PLANAR_FACE) { + removeJunkNodes(); + return; + } + + // F I N D I N T E R S E C T I O N P A R T + + if (testEdgeVsEdge(edge1, edge2) == 0) return; + + // C O N S I D E R D I F F E R E N T C A S E S + + if (irep1 == INTERSECTION && irep2 == INTERSECTION) caseII(edge1, edge2); + if (irep1 == INTERSECTION && irep2 == EDGE) caseIE(edge1, edge2); + if (irep1 == EDGE && irep2 == INTERSECTION) caseIE(edge2, edge1); + if (irep1 == EDGE && irep2 == EDGE) caseEE(edge1, edge2); + removeJunkNodes(); + +} + +void BooleanProcessor::invertNewEdges(int iface) +/*********************************************************************** + * * + * Name: BooleanProcessor::invertNewEdges Date: 04.02.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Invert direction of new edges * + * * + ***********************************************************************/ +{ + int iedge = faces[iface].inew; + while (iedge > 0) { + edges[iedge].invert(); + iedge = edges[iedge].inext; + } +} + +void BooleanProcessor::checkDoubleEdges(int) +/*********************************************************************** + * * + * Name: BooleanProcessor::checkDoubleEdges Date: 04.02.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Eliminate duplication of edges * + * * + ***********************************************************************/ +{ + +} + +void BooleanProcessor::assembleFace(int what, int iface) +/*********************************************************************** + * * + * Name: BooleanProcessor::assembleFace Date: 19.02.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Assemble face * + * * + ***********************************************************************/ +{ + // A S S E M B L E N E W F A C E + + int ihead; // head of the list of edges for new face + int icur; // current edge in the list - last edge inserted to the list + int *ilink; // pointer to the current link + int ifirst; // first node of a contour + int *i; // pointer to the index of the current edge in a loop + int ioldflag=0; // is set if an edge from iold has been taken + +#define INSERT_EDGE_TO_THE_LIST(A) \ +*ilink = A; ilink = &edges[A].inext; *ilink = 0 + + ExtFace& face = faces[iface]; //G.Barrand : optimize. + ilink = &ihead; + for(;;) { + if (face.inew == 0) break; + + // S T A R T N E W C O N T O U R + + icur = face.inew; + face.inew = edges[icur].inext; + INSERT_EDGE_TO_THE_LIST(icur); + ifirst = edges[icur].i1; + + // C O N S T R U C T T H E C O N T O U R + + for (;;) { + i = &face.inew; + ExtEdge& edge_cur = edges[icur]; + while(*i > 0) { + ExtEdge& edge_i = edges[*i]; + if (edge_i.i1 == edge_cur.i2) break; + i = &edge_i.inext; + } + if (*i == 0) { + i = &face.iold; + while(*i > 0) { + ExtEdge& edge_i = edges[*i]; + if (edge_i.i1 == edge_cur.i2) { + ioldflag = 1; + break; + } + i = &edge_i.inext; + } + } + if (*i > 0) { + icur = *i; + *i = edges[icur].inext; + INSERT_EDGE_TO_THE_LIST(icur); + if (edges[icur].i2 == ifirst) { break; } else { continue; } + }else{ + processor_error = 1; +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::assembleFace(" << iface << ") : " + << "could not find next edge of the contour" + << G4endl; +#endif + face.inew = DEFECTIVE_FACE; + return; + } + } + } + + // C H E C K O R I G I N A L C O N T O U R + + int iedge; + iedge = face.iold; + if (what == 0 && ioldflag == 0 && iedge > 0) { + for (;;) { + if (edges[iedge].inext > 0) { + if (edges[iedge].i2 == edges[edges[iedge].inext].i1) { + iedge = edges[iedge].inext; + }else{ + break; + } + }else{ + if (edges[iedge].i2 == edges[face.iold].i1) { + edges[iedge].inext = ihead; // set new face + return; + }else{ + break; + } + } + } + } + + // M A R K U N S U I T A B L E N E I G H B O U R I N G F A C E S + + int iface2; + iedge = face.iold; + while(iedge > 0) { + iface2 = edges[iedge].iface2; + if (faces[iface2].inew == 0) faces[iface2].inew = UNSUITABLE_FACE; + iedge = edges[iedge].inext; + } + face.iold = ihead; // set new face +} + +void BooleanProcessor::assembleNewFaces(int what, int ihead) +/*********************************************************************** + * * + * Name: BooleanProcessor::assembleNewFaces Date: 30.01.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Assemble internal or external parts of faces * + * * + ***********************************************************************/ +{ + int iface = ihead; + while(iface > 0) { + if (faces[iface].inew > 0) { + if (what != 0) invertNewEdges(iface); + checkDoubleEdges(iface); + assembleFace(what, iface); + faces[iface].inew = + (faces[iface].iold == 0) ? UNSUITABLE_FACE : NEW_FACE; + } + iface = faces[iface].inext; + } +} + +void BooleanProcessor::initiateLists() +/*********************************************************************** + * * + * Name: BooleanProcessor::initiateLists Date: 28.02.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Initiate lists of faces. * + * * + ***********************************************************************/ +{ + int i, iface; + + // R E S E T L I S T S O F F A C E S + + result_faces.clean(); + suitable_faces.clean(); + unsuitable_faces.clean(); + unknown_faces.clean(); + + // I N I T I A T E T H E L I S T S + + iface = iout1; + while (iface > 0) { + i = iface; + iface = faces[i].inext; + if (operation == OP_INTERSECTION) { + unsuitable_faces.push_back(i); + faces[i].inew = UNSUITABLE_FACE; + }else{ + suitable_faces.push_back(i); + faces[i].inew = ORIGINAL_FACE; + } + } + iface = iout2; + while (iface > 0) { + i = iface; + iface = faces[i].inext; + if (operation == OP_UNION) { + suitable_faces.push_back(i); + faces[i].inew = ORIGINAL_FACE; + }else{ + unsuitable_faces.push_back(i); + faces[i].inew = UNSUITABLE_FACE; + } + } + + iface = iunk1; + while (iface > 0) { + i = iface; + iface = faces[i].inext; + unknown_faces.push_back(i); + } + iface = iunk2; + while (iface > 0) { + i = iface; + iface = faces[i].inext; + if (operation == OP_SUBTRACTION) faces[i].invert(); + unknown_faces.push_back(i); + } + + iface = ifaces1; + while (iface > 0) { + i = iface; + iface = faces[i].inext; + switch(faces[i].inew) { + case UNKNOWN_FACE: + unknown_faces.push_back(i); + break; + case ORIGINAL_FACE: case NEW_FACE: + suitable_faces.push_back(i); + break; + case UNSUITABLE_FACE: + unsuitable_faces.push_back(i); + break; + default: + faces[i].iprev = 0; + faces[i].inext = 0; + break; + } + } + iface = ifaces2; + while (iface > 0) { + i = iface; + iface = faces[i].inext; + if (operation == OP_SUBTRACTION) faces[i].invert(); + switch(faces[i].inew) { + case UNKNOWN_FACE: + unknown_faces.push_back(i); + break; + case ORIGINAL_FACE: case NEW_FACE: + suitable_faces.push_back(i); + break; + case UNSUITABLE_FACE: + unsuitable_faces.push_back(i); + break; + default: + faces[i].iprev = 0; + faces[i].inext = 0; + break; + } + } + ifaces1 = ifaces2 = iout1 = iout2 = iunk1 = iunk2 = 0; +} + +void BooleanProcessor::assemblePolyhedra() +/*********************************************************************** + * * + * Name: BooleanProcessor::assemblePolyhedra() Date: 10.12.99 * + * Author: E.Chernyaev Revised: * + * * + * Function: Collect suitable faces and remove unsuitable ones. * + * * + ***********************************************************************/ +{ + int i, iedge, iface; + + // L O O P A L O N G S U I T A B L E F A C E S + + iface = suitable_faces.front(); + while(iface > 0) { + i = iface; + iedge = faces[i].iold; + while(iedge > 0) { + iface = edges[iedge].iface2; + if (faces[iface].inew == UNKNOWN_FACE) { + unknown_faces.remove(iface); + suitable_faces.push_back(iface); + faces[iface].inew = ORIGINAL_FACE; + } + iedge = edges[iedge].inext; + } + iface = faces[i].inext; + suitable_faces.remove(i); + result_faces.push_back(i); + } + if (unknown_faces.front() == 0) return; + + // L O O P A L O N G U N S U I T A B L E F A C E S + + iface = unsuitable_faces.front(); + while(iface > 0) { + i = iface; + iedge = faces[i].iold; + while(iedge > 0) { + iface = edges[iedge].iface2; + if (faces[iface].inew == UNKNOWN_FACE) { + unknown_faces.remove(iface); + unsuitable_faces.push_back(iface); + faces[iface].inew = UNSUITABLE_FACE; + } + iedge = edges[iedge].inext; + } + iface = faces[i].inext; + //unsuitable_faces.remove(i); + } + +#ifdef MOD_PONCE + //G.Barrand : begin + /* From S.Ponce + At last, there is a problem in the assemblePolyhedra method. At least, I + think it is there. The problem deals with boolean operations on solids, + when one of the two contains entirely the other one. It has no sense for + intersection and union but still has sense for subtraction. In this + case, faces from the inner solid are stored in the unknown_faces + FaceList. And an error occurs in the execute method. This may be correct + for intersection and union but in the case of subtraction, one should do + that in assemblePolyhedra : + */ + // Unknown faces are actually suitable face !!! + iface = unknown_faces.front(); + while(iface > 0) { + i = iface; + faces[i].inew = ORIGINAL_FACE; + iface = faces[i].inext; + unknown_faces.remove(i); + result_faces.push_back(i); + } + /* + Otherwise, the inner hole that the second solid was building in the + first one does not exist. I'm not very clear on what to do for unions + and intersections. I think this kind of situation should be detected and + one of the solid should simply be ignored. + */ + //G.Barrand : end +#else + //R.T.Jones : begin + /* If there are faces left on the unknown_faces list, it is presumed to + * be because the boolean operation was requested between volumes whose + * faces never intersect. What to do in this case depends on type of + * operation, and whether the two volumes are non-overlapping or if one + * of the two volumes lies completely inside the other. Listed below + * is the result that should be returned in each case. + * + * 1. Does first vertex of the operand volume lie inside the original? + * a. yes : case (operation) + * SUBTRACTION : return all faces, both volumes + * INTERSECTION : return faces of operand volume + * UNION : return faces of the original volume + * b. no : continue + * 2. Does first vertex of the original volume lie inside the operand? + * a. yes : case (operation) + * SUBTRACTION : return null polyhedron + * INTERSECTION : return faces of original volume + * UNION : return faces of the operand volume + * b. no : case (operation) + * SUBTRACTION : return original polyhedron + * INTERSECTION : return null polyhedron + * UNION : return all faces, both volumes + */ + + int icand = unknown_faces.front(); + if (icand > 0) { + bool accept_cand = false; + bool accept_left = false; + int ileft = unsuitable_faces.front(); + if (ileft == 0) ileft = result_faces.front(); + int iedge = faces[ileft].iedges[0]; + int inode = edges[iedge].i1; + if (isInside(nodes[inode].v,unknown_faces)) { + switch (operation) { + case OP_SUBTRACTION : + accept_cand = true; + accept_left = true; + break; + case OP_INTERSECTION : + accept_cand = false; + accept_left = true; + break; + case OP_UNION : + accept_cand = true; + accept_left = false; + } + } + else { + iedge = faces[icand].iedges[0]; + inode = edges[iedge].i1; + if (isInside(nodes[inode].v,unsuitable_faces)) { + switch (operation) { + case OP_SUBTRACTION : + accept_cand = false; + accept_left = false; + break; + case OP_INTERSECTION : + accept_cand = true; + accept_left = false; + break; + case OP_UNION : + accept_cand = false; + accept_left = true; + } + } + else if (isInside(nodes[inode].v,result_faces)) { + switch (operation) { + case OP_SUBTRACTION : + accept_cand = true; + accept_left = false; + break; + case OP_INTERSECTION : + accept_cand = true; + accept_left = false; + break; + case OP_UNION : + accept_cand = false; + accept_left = false; + } + } + else { + switch (operation) { + case OP_SUBTRACTION : + accept_cand = true; + accept_left = false; + break; + case OP_INTERSECTION : + accept_cand = false; + accept_left = false; + break; + case OP_UNION : + accept_cand = true; + accept_left = true; + } + } + } + iface = unknown_faces.front(); + while (iface > 0) { + i = iface; + iface = faces[i].inext; + unknown_faces.remove(i); + if (accept_cand) { + faces[i].inew = ORIGINAL_FACE; + result_faces.push_back(i); + } + else { + faces[i].inew = UNSUITABLE_FACE; + } + } + iface = unsuitable_faces.front(); + while (iface > 0) { + i = iface; + iface = faces[i].inext; + unsuitable_faces.remove(i); + if (accept_left) { + faces[i].inew = ORIGINAL_FACE; + result_faces.push_back(i); + } + else { + faces[i].inew = UNSUITABLE_FACE; + } + } + } + //R.T.Jones : end +#endif +} + +inline void +BooleanProcessor::findABC(double x1, double y1, double x2, double y2, + double &a, double &b, double &c) const +/*********************************************************************** + * * + * Name: BooleanProcessor::findABC Date: 07.03.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Find line equation Ax+By+C=0 * + * * + ***********************************************************************/ +{ + double w; + a = y1 - y2; + b = x2 - x1; + //G.Barrand : w = std::abs(a)+std::abs(b); + w = ::fabs(a)+::fabs(b); //G.Barrand + a /= w; + b /= w; + c = -(a*x2 + b*y2); +} + +int BooleanProcessor::checkDirection(double *x, double *y) const +/*********************************************************************** + * * + * Name: BooleanProcessor::checkDirection Date: 06.03.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Check direction of line 1-4 * + * * + ***********************************************************************/ +{ + double a1, b1, c1, a2, b2, c2, d1, d2; + + // T E S T L I N E 1 - 4 V S E X T E R N A L C O N T O U R + + findABC(x[0], y[0], x[1], y[1], a1, b1, c1); + findABC(x[1], y[1], x[2], y[2], a2, b2, c2); + d1 = a1*x[4] + b1*y[4] + c1; + d2 = a2*x[4] + b2*y[4] + c2; + if (d1 <= del && d2 <= del) return 1; + if (! (d1 > del && d2 > del)) { + if ( a1*x[2] + b1*y[2] + c1 >= -del) return 1; + } + + // T E S T L I N E 1 - 4 V S I N T E R N A L C O N T O U R + + findABC(x[3], y[3], x[4], y[4], a1, b1, c1); + findABC(x[4], y[4], x[5], y[5], a2, b2, c2); + d1 = a1*x[1] + b1*y[1] + c1; + d2 = a2*x[1] + b2*y[1] + c2; + if (d1 <= del && d2 <= del) return 1; + if (!(d1 > del && d2 > del)) { + if ( a1*x[5] + b1*y[5] + c1 >= -del) return 1; + } + return 0; +} + +int BooleanProcessor::checkIntersection(int ix, int iy, int i1, int i2) const +/*********************************************************************** + * * + * Name: BooleanProcessor::checkDirection Date: 06.03.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Check line i1-i2 on intersection with contours * + * * + ***********************************************************************/ +{ + // F I N D L I N E E Q U A T I O N + + double x1, y1, x2, y2, a1, b1, c1; + x1 = nodes[i1].v[ix]; + y1 = nodes[i1].v[iy]; + x2 = nodes[i2].v[ix]; + y2 = nodes[i2].v[iy]; + findABC(x1, y1, x2, y2, a1, b1, c1); + + // L O O P A L O N G E X T E R N A L C O N T O U R S + + int icontour, iedge, k1, k2; + double x3, y3, x4, y4, a2, b2, c2, d1, d2; + for(icontour=0; icontour<(int)external_contours.size(); icontour++) { + iedge = external_contours[icontour]; + while(iedge > 0) { + k1 = edges[iedge].i1; + k2 = edges[iedge].i2; + iedge = edges[iedge].inext; + if (k1 == i1 || k2 == i1) continue; + if (k1 == i2 || k2 == i2) continue; + x3 = nodes[k1].v[ix]; + y3 = nodes[k1].v[iy]; + x4 = nodes[k2].v[ix]; + y4 = nodes[k2].v[iy]; + d1 = a1*x3 + b1*y3 + c1; + d2 = a1*x4 + b1*y4 + c1; + if (d1 > del && d2 > del) continue; + if (d1 < -del && d2 < -del) continue; + + findABC(x3, y3, x4, y4, a2, b2, c2); + d1 = a2*x1 + b2*y1 + c2; + d2 = a2*x2 + b2*y2 + c2; + if (d1 > del && d2 > del) continue; + if (d1 < -del && d2 < -del) continue; + return 1; + } + } + + // L O O P A L O N G E X T E R N A L C O N T O U R S + + for(icontour=0; icontour<(int)internal_contours.size(); icontour++) { + iedge = internal_contours[icontour]; + while(iedge > 0) { + k1 = edges[iedge].i1; + k2 = edges[iedge].i2; + iedge = edges[iedge].inext; + if (k1 == i1 || k2 == i1) continue; + if (k1 == i2 || k2 == i2) continue; + x3 = nodes[k1].v[ix]; + y3 = nodes[k1].v[iy]; + x4 = nodes[k2].v[ix]; + y4 = nodes[k2].v[iy]; + d1 = a1*x3 + b1*y3 + c1; + d2 = a1*x4 + b1*y4 + c1; + if (d1 > del && d2 > del) continue; + if (d1 < -del && d2 < -del) continue; + + findABC(x3, y3, x4, y4, a2, b2, c2); + d1 = a2*x1 + b2*y1 + c2; + d2 = a2*x2 + b2*y2 + c2; + if (d1 > del && d2 > del) continue; + if (d1 < -del && d2 < -del) continue; + return 1; + } + } + return 0; +} + +void BooleanProcessor::mergeContours(int ix, int iy, int kext, int kint) +/*********************************************************************** + * * + * Name: BooleanProcessor::mergeContours Date: 06.03.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Attemp to merge internal contour with external one * + * * + ***********************************************************************/ +{ + int i1ext, i2ext, i1int, i2int, i, k[6]; + double x[6], y[6]; + + // L O O P A L O N G E X T E R N A L C O N T O U R + + i1ext = external_contours[kext]; + while (i1ext > 0) { + i2ext = edges[i1ext].inext; + if (i2ext == 0) i2ext = external_contours[kext]; + k[0] = edges[i1ext].i1; + k[1] = edges[i1ext].i2; + k[2] = edges[i2ext].i2; + for (i=0; i<3; i++) { + x[i] = nodes[k[i]].v[ix]; + y[i] = nodes[k[i]].v[iy]; + } + + // L O O P A L O N G I N T E R N A L C O N T O U R + + i1int = internal_contours[kint]; + while (i1int > 0) { + i2int = edges[i1int].inext; + if (i2int == 0) i2int = internal_contours[kint]; + k[3] = edges[i1int].i1; + k[4] = edges[i1int].i2; + k[5] = edges[i2int].i2; + for (i=3; i<6; i++) { + x[i] = nodes[k[i]].v[ix]; + y[i] = nodes[k[i]].v[iy]; + } + + // T E S T L I N E K1 - K4 + // I F O K T H E N M E R G E C O N T O U R S + + if (checkDirection(x, y) == 0) { + if (checkIntersection(ix, iy, k[1], k[4]) == 0) { + i = i1int; + for(;;) { + if (edges[i].inext == 0) { + edges[i].inext = internal_contours[kint]; + internal_contours[kint] = 0; + break; + }else{ + i = edges[i].inext; + } + } + i = edges[i1int].iface1; + edges.push_back(ExtEdge(k[1], k[4], i, -(int(edges.size())+1), -1)); + edges.back().inext = i2int; + edges.push_back(ExtEdge(k[4], k[1], i, -(int(edges.size())-1), -1)); + edges.back().inext = edges[i1ext].inext; + edges[i1ext].inext = edges.size()-2; + edges[i1int].inext = edges.size()-1; + return; + } + } + i1int = edges[i1int].inext; + } + i1ext = edges[i1ext].inext; + } +} + +int +BooleanProcessor::checkTriangle(int iedge1, int iedge2, int ix, int iy) const +/*********************************************************************** + * * + * Name: BooleanProcessor::checkTriangle Date: 08.03.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Check triangle for correctness * + * * + ***********************************************************************/ +{ + int k[3]; + double x[3], y[3]; + double a1, b1, c1; + + k[0] = edges[iedge1].i1; + k[1] = edges[iedge1].i2; + k[2] = edges[iedge2].i2; + for (int i=0; i<3; i++) { + x[i] = nodes[k[i]].v[ix]; + y[i] = nodes[k[i]].v[iy]; + } + + // C H E C K P R I N C I P A L C O R R E C T N E S S + + findABC(x[2], y[2], x[0], y[0], a1, b1, c1); + if (a1*x[1]+b1*y[1]+c1 <= 0.1*del) return 1; + + // C H E C K T H A T T H E R E I S N O P O I N T S I N S I D E + + int inode, iedge; + double a2, b2, c2, a3, b3, c3; + + findABC(x[0], y[0], x[1], y[1], a2, b2, c2); + findABC(x[1], y[1], x[2], y[2], a3, b3, c3); + iedge = iedge2; + for (;;) { + iedge = edges[iedge].inext; + if (edges[iedge].inext == iedge1) return 0; + inode = edges[iedge].i2; + if (inode == k[0]) continue; + if (inode == k[1]) continue; + if (inode == k[2]) continue; + x[1] = nodes[inode].v[ix]; + y[1] = nodes[inode].v[iy]; + if (a1*x[1]+b1*y[1]+c1 < -0.1*del) continue; + if (a2*x[1]+b2*y[1]+c2 < -0.1*del) continue; + if (a3*x[1]+b3*y[1]+c3 < -0.1*del) continue; + return 1; + } +} + +void BooleanProcessor::triangulateContour(int ix, int iy, int ihead) +/*********************************************************************** + * * + * Name: BooleanProcessor::triangulateContour Date: 06.03.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Triangulate external contour * + * * + ***********************************************************************/ +{ + + //G4cout << "Next Countour" << G4endl; + //int draw_flag = 0; + //if (draw_flag) draw_contour(5, 3, ihead); + + // C L O S E C O N T O U R + + int ipnext = ihead, nnode = 1; + for (;;) { + if (edges[ipnext].inext > 0) { + ipnext = edges[ipnext].inext; + nnode++; + }else{ + edges[ipnext].inext = ihead; + break; + } + } + + // L O O P A L O N G C O N T O U R + + //G4cerr << "debug : contour : begin : =================" << G4endl; + //dump();//debug + + int iedge1, iedge2, iedge3, istart = 0; + for (;;) { + iedge1 = edges[ipnext].inext; + iedge2 = edges[iedge1].inext; +/* + G4cerr << "debug :" + << " ipnext " << ipnext + << " iedge1 " << iedge1 + << " iedge2 " << iedge2 + << " : istart " << istart + << G4endl; +*/ + if (istart == 0) { + istart = iedge1; + if (nnode <= 3) { + iedge3 = edges[iedge2].inext; + edges[iedge1].iface1 = faces.size(); + edges[iedge2].iface1 = faces.size(); + edges[iedge3].iface1 = faces.size(); + edges[iedge3].inext = 0; + faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ? + faces.back().iold = iedge1; + faces.back().inew = ORIGINAL_FACE; + + //if (draw_flag) draw_contour(4, 2, iedge1); + + break; + } + }else if (istart == iedge1) { + processor_error = 1; +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::triangulateContour : " + << "could not generate a triangle (infinite loop)" + << G4endl; +#endif + break; + } + + // C H E C K C O R E C T N E S S O F T H E T R I A N G L E + + if (checkTriangle(iedge1,iedge2,ix,iy) != 0) { + ipnext = edges[ipnext].inext; + continue; + } + + // M O D I F Y C O N T O U R + + int i1 = edges[iedge1].i1; + int i3 = edges[iedge2].i2; + int iface1 = edges[iedge1].iface1; + int iface2 = faces.size(); + + edges[ipnext].inext = edges.size(); + edges.push_back(ExtEdge(i1, i3, iface1, -(int(edges.size())+1), -1)); + edges.back().inext = edges[iedge2].inext; + + // A D D N E W T R I A N G L E T O T H E L I S T + + edges[iedge2].inext = edges.size(); + edges.push_back(ExtEdge(i3, i1, iface2, -(int(edges.size())-1), -1)); + faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ? + faces.back().iold = iedge1; + faces.back().inew = ORIGINAL_FACE; + edges[iedge1].iface1 = iface2; + edges[iedge2].iface1 = iface2; + ipnext = edges[ipnext].inext; + istart = 0; + nnode--; + + //if (draw_flag) draw_contour(4, 2, iedge1); + + } +} + +void BooleanProcessor::modifyReference(int iface, int i1, int i2, int iref) +/*********************************************************************** + * * + * Name: BooleanProcessor::modifyReference Date: 13.03.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Modify reference to the neighbouring face * + * * + ***********************************************************************/ +{ + int iedge = faces[iface].iold; + while (iedge > 0) { + if (edges[iedge].i1 == i2 && edges[iedge].i2 == i1) { + edges[iedge].iface2 = iref; + return; + } + iedge = edges[iedge].inext; + } + processor_error = 1; +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::modifyReference : could not find the edge, " + << "iface=" << iface << ", i1,i2=" << i1 << "," << i2 << ", iref=" << iref + << G4endl; +#endif +} + +void BooleanProcessor::triangulateFace(int iface) +/*********************************************************************** + * * + * Name: BooleanProcessor::triangulateFace Date: 02.03.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Triangulation of an extended face * + * * + ***********************************************************************/ +{ + + // F I N D M A X C O M P O N E N T O F T H E N O R M A L + // S E T IX, IY, IZ + +#ifdef BP_GEANT4 //G.Barrand + HVNormal3D normal = faces[iface].plane.normal(); +#else + const HVNormal3D& normal = faces[iface].plane.getNormal(); +#endif + int ix, iy, iz = 0; + //G.Barrand : if (std::abs(normal[1]) > std::abs(normal[iz])) iz = 1; + //G.Barrand : if (std::abs(normal[2]) > std::abs(normal[iz])) iz = 2; + if (::fabs(normal[1]) > ::fabs(normal[iz])) iz = 1; //G.Barrand + if (::fabs(normal[2]) > ::fabs(normal[iz])) iz = 2; //G.Barrand + if (normal[iz] > 0) { + ix = (iz+1)%3; iy = (ix+1)%3; + }else{ + iy = (iz+1)%3; ix = (iy+1)%3; + } + + // F I L L L I S T S O F C O N T O U R S + + external_contours.clear(); + internal_contours.clear(); + double z; + int i1, i2, ifirst, iedge, icontour = faces[iface].iold; + while (icontour > 0) { + iedge = icontour; + ifirst = edges[iedge].i1; + z = 0.0; + for(;;) { + if (iedge > 0) { + i1 = edges[iedge].i1; + i2 = edges[iedge].i2; + ExtNode& node_1 = nodes[i1]; + ExtNode& node_2 = nodes[i2]; + z += node_1.v[ix]*node_2.v[iy]-node_2.v[ix]*node_1.v[iy]; + if (ifirst != i2) { + iedge = edges[iedge].inext; + continue; + }else{ + if (z > del*del) { + external_contours.push_back(icontour); + }else if (z < -del*del) { + internal_contours.push_back(icontour); + }else{ + processor_error = 1; +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::triangulateFace : too small contour" + << G4endl; +#endif + } + icontour = edges[iedge].inext; + edges[iedge].inext = 0; + break; + } + }else{ + processor_error = 1; +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::triangulateFace : broken contour" + << G4endl; +#endif + icontour = 0; + break; + } + } + } + + // G E T R I D O F I N T E R N A L C O N T O U R S + + int kint, kext; + for (kint=0; kint < (int)internal_contours.size(); kint++) { + for (kext=0; kext < (int)external_contours.size(); kext++) { + mergeContours(ix, iy, kext, kint); + if (internal_contours[kint] == 0) break; + } + if (kext == (int)external_contours.size()) { + processor_error = 1; +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::triangulateFace : " + << "could not merge internal contour " << kint + << G4endl; +#endif + } + } + + // T R I A N G U L A T E C O N T O U R S + + int nface = faces.size(); + for (kext=0; kext < (int)external_contours.size(); kext++) { + triangulateContour(ix, iy, external_contours[kext]); +#ifdef BP_DEBUG + if(processor_error) { //G.Barrand + G4cerr + << "BooleanProcessor::triangulateFace : " + << "triangulateContour failed." + << G4endl; + break; //G.Barrand : ok ? + } +#endif + } + faces[iface].inew = UNSUITABLE_FACE; + + // M O D I F Y R E F E R E N C E S + + for (int ifa=nface; ifa<(int)faces.size(); ifa++) { + iedge = faces[ifa].iold; + while (iedge > 0) { + if (edges[iedge].iface1 != ifa) { + processor_error = 1; +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::triangulateFace : wrong reference to itself, " + << "iface=" << ifa << ", iface1=" << edges[iedge].iface1 + << G4endl; +#endif + }else if (edges[iedge].iface2 > 0) { + modifyReference(edges[iedge].iface2, + edges[iedge].i1, edges[iedge].i2, ifa); + }else if (edges[iedge].iface2 < 0) { + edges[iedge].iface2 = edges[-edges[iedge].iface2].iface1; + } + iedge = edges[iedge].inext; + } + } +} + +HepPolyhedron BooleanProcessor::createPolyhedron() +/*********************************************************************** + * * + * Name: BooleanProcessor::createPolyhedron() Date: 14.03.00 * + * Author: E.Chernyaev Revised: * + * * + * Function: Create HepPolyhedron. * + * * + ***********************************************************************/ +{ + int i, iedge, nnode = 0, nface = 0; + + // R E N U M E R A T E N O D E S A N D F A C E S + + for (i=1; i<(int)nodes.size(); i++) nodes[i].s = 0; + + for (i=1; i<(int)faces.size(); i++) { + if (faces[i].inew == ORIGINAL_FACE) { + faces[i].inew = ++nface; + iedge = faces[i].iold; + while (iedge > 0) { + nodes[edges[iedge].i1].s = 1; + iedge = edges[iedge].inext; + } + }else{ + faces[i].inew = 0; + } + } + + for (i=1; i<(int)nodes.size(); i++) { + if (nodes[i].s == 1) nodes[i].s = ++nnode; + } + + // A L L O C A T E M E M O R Y + + ExtPolyhedron polyhedron; + if (nface == 0) return polyhedron; + polyhedron.AllocateMemory(nnode, nface); + + // S E T N O D E S + + for (i=1; i<(int)nodes.size(); i++) { + if (nodes[i].s != 0) polyhedron.pV[nodes[i].s] = nodes[i].v; + } + + // S E T F A C E S + + int k = 0, v[4] = {0,0,0,0}, f[4] = {0,0,0,0}; + for (i=1; i<(int)faces.size(); i++) { + if (faces[i].inew == 0) continue; + v[3] = f[3] = k = 0; + iedge = faces[i].iold; + while (iedge > 0) { + if (k > 3) { + G4cerr + << "BooleanProcessor::createPolyhedron : too many edges" + << G4endl; + break; + } + v[k] = nodes[edges[iedge].i1].s; + if (edges[iedge].ivis < 0) v[k] = -v[k]; + f[k] = faces[edges[iedge].iface2].inew; + iedge = edges[iedge].inext; + k++; + } + if (k < 3) { + G4cerr + << "BooleanProcessor::createPolyhedron : " + << "face has only " << k << " edges" + << G4endl; + } + polyhedron.pF[faces[i].inew] = + G4Facet(v[0],f[0], v[1],f[1], v[2],f[2], v[3],f[3]); + } + return polyhedron; +} + +G4ThreadLocal int BooleanProcessor::ishift = 0; //G.Barrand +int BooleanProcessor::get_shift() { return ishift;} //G.Barrand +void BooleanProcessor::set_shift(int a_shift) { ishift = a_shift;} //G.Barrand +#define NUM_SHIFT 8 +int BooleanProcessor::get_num_shift() { return NUM_SHIFT;} //G.Barrand + +HepPolyhedron BooleanProcessor::execute(int op, + const HepPolyhedron & a, + const HepPolyhedron & b, + int& err) //G.Barrand +/*********************************************************************** + * * + * Name: BooleanProcessor::execute Date: 10.12.99 * + * Author: E.Chernyaev Revised: * + * * + * Function: Execute boolean operation. * + * * + ***********************************************************************/ +{ + //static int ishift = 0; //G.Barrand + //static double shift[8][3] = { + static const double shift[NUM_SHIFT][3] = { //G.Barrand + { 31, 23, 17}, + { -31, -23, -17}, + { -23, 17, 31}, + { 23, -17, -31}, + { -17, -31, 23}, + { 17, 31, -23}, + { 31, -23, 17}, + { -31, 23, -17} + }; + +/* + G4cerr << "BooleanProcessor::execute : ++++++++++++++++++++++" + << a.getName().getString() + << b.getName().getString() + << G4endl; +*/ + + // I N I T I A T E P R O C E S S O R + + processor_error = 0; + operation = op; + nodes.clear(); nodes.push_back(CRAZY_POINT); + edges.clear(); edges.push_back(ExtEdge()); + faces.clear(); faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ? + + // T A K E P O L Y H E D R A + + ifaces1 = faces.size(); takePolyhedron(a,0,0,0); + ifaces2 = faces.size(); takePolyhedron(b,0,0,0); + + if (processor_error) { // corrupted polyhedron + G4cerr + << "BooleanProcessor: corrupted input polyhedron" + << G4endl; + err = processor_error; //G.Barrand + return HepPolyhedron(); + } + if (ifaces1 == ifaces2) { // a is empty + err = processor_error; //G.Barrand + switch (operation) { + case OP_UNION: + return b; + case OP_INTERSECTION: + G4cerr + << "BooleanProcessor: intersection with empty polyhedron" + << G4endl; + return HepPolyhedron(); + case OP_SUBTRACTION: + G4cerr + << "BooleanProcessor: subtraction from empty polyhedron" + << G4endl; + return HepPolyhedron(); + } + } + if (ifaces2 == (int)faces.size()) { // b is empty + err = processor_error; //G.Barrand + switch (operation) { + case OP_UNION: + return a; + case OP_INTERSECTION: + G4cerr + << "BooleanProcessor: intersection with empty polyhedron" + << G4endl; + return HepPolyhedron(); + case OP_SUBTRACTION: + return a; + } + } + + // S E T I N I T I A L M I N - M A X A N D T O L E R A N C E + + del = findMinMax(); + + // W O R K A R O U N D T O A V O I D I E A N D E E + +/* +#define PROCESSOR_ERROR(a_what) \ + G4cerr << "BooleanProcessor: boolean operation problem (" << a_what \ + << "). Try again with other shifts."\ + << G4endl; +*/ +#define PROCESSOR_ERROR(a_what) + + unsigned int try_count = 1; + while(true) { //G.Barrand + + double ddxx = del*shift[ishift][0]; + double ddyy = del*shift[ishift][1]; + double ddzz = del*shift[ishift][2]; + ishift++; if (ishift == get_num_shift()) ishift = 0; + + processor_error = 0; //G.Barrand + operation = op; + nodes.clear(); nodes.push_back(CRAZY_POINT); + edges.clear(); edges.push_back(ExtEdge()); + faces.clear(); faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ? + + ifaces1 = faces.size(); takePolyhedron(a,0,0,0); + ifaces2 = faces.size(); takePolyhedron(b,ddxx,ddyy,ddzz); + + if (processor_error) { PROCESSOR_ERROR(1) } //G.Barrand + + del = findMinMax(); + + // P R E S E L E C T O U T S I D E F A C E S + + iout1 = iout2 = 0; + selectOutsideFaces(ifaces1, iout1); + selectOutsideFaces(ifaces2, iout2); + + if (processor_error) { PROCESSOR_ERROR(2) } //G.Barrand + + // P R E S E L E C T N O I N T E R S E C T I O N F A C E S + + int ifa1, ifa2; + iunk1 = iunk2 = 0; + if (iout1 != 0 || iout2 != 0) { + for(;;) { + ifa1 = iunk1; + ifa2 = iunk2; + selectOutsideFaces(ifaces1, iunk1); + selectOutsideFaces(ifaces2, iunk2); + if (iunk1 == ifa1 && iunk2 == ifa2) break; + findMinMax(); + } + } + + if (processor_error) { PROCESSOR_ERROR(3) } //G.Barrand + + // F I N D N E W E D G E S + + if (ifaces1 != 0 && ifaces2 != 0 ) { + ifa1 = ifaces1; + while (ifa1 > 0) { + ifa2 = ifaces2; + while (ifa2 > 0) { + testFaceVsFace(ifa1, ifa2); + ifa2 = faces[ifa2].inext; + } + ifa1 = faces[ifa1].inext; + } + } + if (processor_error) { PROCESSOR_ERROR(4) } //G.Barrand + + // C O N S T R U C T N E W F A C E S + + assembleNewFaces((operation == OP_INTERSECTION) ? 1 : 0, ifaces1); + if (processor_error) { PROCESSOR_ERROR(5) } //G.Barrand + assembleNewFaces((operation == OP_UNION) ? 0 : 1, ifaces2); + if (processor_error) { PROCESSOR_ERROR(6) } //G.Barrand + + // A S S E M B L E S U I T A B L E F A C E S + + initiateLists(); + assemblePolyhedra(); + if (unknown_faces.front() != 0) { + processor_error = 1; +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::execute : unknown faces !!!" + << G4endl; +#endif + } + if (processor_error) { PROCESSOR_ERROR(7) } //G.Barrand + + // T R I A N G U L A T E A C C E P T E D F A C E S + + ifa1 = result_faces.front(); + while (ifa1 > 0) { + ifa2 = ifa1; + ifa1 = faces[ifa2].inext; + if (faces[ifa2].inew == NEW_FACE) triangulateFace(ifa2); + if (processor_error) { + PROCESSOR_ERROR(8) //G.Barrand + break; //G.Barrand + } + } + + if(!processor_error) { +#ifdef BP_DEBUG + if(try_count!=1) { + G4cerr + << "BooleanProcessor::execute : had converged." + << G4endl; + } +#endif + break; + } + + if((int)try_count>get_num_shift()) { +#ifdef BP_DEBUG + /*** Commented out because HepPolyhedron does not have getName...?! + G4cerr << "BooleanProcessor: " + << " all shifts tried. Boolean operation (" << op << ") failure." + << " a name \"" << a.getName().getString() << "\"" + << " b name \"" << b.getName().getString() << "\"" + << G4endl; + ***/ +#endif + err = processor_error; + return a; + } + +#ifdef BP_DEBUG + G4cerr + << "BooleanProcessor::execute : try another tilt..." + << G4endl; +#endif + + try_count++; + + } //G.Barrand : end while shift. +#undef PROCESSOR_ERROR //G.Barrand + + // C R E A T E P O L Y H E D R O N + + err = processor_error; + return createPolyhedron(); +} + + +//#include +//#include +//#include "zbuf.h" +//void BooleanProcessor::draw() +/*********************************************************************** + * * + * Name: BooleanProcessor::draw Date: 10.12.99 * + * Author: E.Chernyaev Revised: * + * * + * Function: Draw * + * * + ***********************************************************************/ +/* +{ + int II; + int icol, i1, i2, iedge, iface, ilist[4]; + float p1[3], p2[3]; + + ilist[0] = ifaces1; + ilist[1] = ifaces2; + ilist[2] = iout1; + ilist[3] = iout2; + + for (int i=0; i<4; i++) { + + if (i == 0) G4cout << "========= Ifaces_1" << G4endl; + if (i == 1) G4cout << "========= Ifaces_2" << G4endl; + if (i == 2) G4cout << "========= Iout_1" << G4endl; + if (i == 3) G4cout << "========= Iout_2" << G4endl; + + icol = i+1; + iface = ilist[i]; + while (iface > 0) { + + G4cout << "iface = " << iface << G4endl; + G4cout << "--- iold" << G4endl; + + iedge = faces[iface].iold; + icol = 2; + + while (iedge > 0) { + + G4cout << " iegde = " << iedge + << " i1,i2 =" << edges[iedge].i1 << "," << edges[iedge].i2 + << " iface1,iface2 = " + << edges[iedge].iface1 << "," << edges[iedge].iface2 + << G4endl; + + i1 = edges[iedge].i1; + p1[0] = nodes[i1].v.x(); + p1[1] = nodes[i1].v.y(); + p1[2] = nodes[i1].v.z(); + IHWTON(p1,p1); + i2 = edges[iedge].i2; + p2[0] = nodes[i2].v.x(); + p2[1] = nodes[i2].v.y(); + p2[2] = nodes[i2].v.z(); + IHWTON(p2,p2); +// icol = (edges[iedge].ivis > 0) ? 1 : 2; + IHZLIN(icol,p1[0],p1[1],p1[2], p2[0],p2[1],p2[2]); + iedge = edges[iedge].inext; + } + + G4cout << "--- inew" << G4endl; + + iedge = faces[iface].inew; + icol = 3; + + while (iedge > 0) { + + G4cout << " iegde = " << iedge + << " i1,i2 =" << edges[iedge].i1 << "," << edges[iedge].i2 + << " iface1,iface2 = " + << edges[iedge].iface1 << "," << edges[iedge].iface2 + << G4endl; + + i1 = edges[iedge].i1; + p1[0] = nodes[i1].v.x(); + p1[1] = nodes[i1].v.y(); + p1[2] = nodes[i1].v.z(); + IHWTON(p1,p1); + i2 = edges[iedge].i2; + p2[0] = nodes[i2].v.x(); + p2[1] = nodes[i2].v.y(); + p2[2] = nodes[i2].v.z(); + IHWTON(p2,p2); +// icol = (edges[iedge].ivis > 0) ? 1 : 2; + IHZLIN(icol,p1[0],p1[1],p1[2], p2[0],p2[1],p2[2]); + iedge = edges[iedge].inext; + } + iface = faces[iface].inext; + + IHZTOX(0,100,100); + ixupdwi(0); + cin >> II; + ixclrwi(); + IHZCLE(0); + } + } +} +*/ + +/* +//-------------------------------------------------------------------- +void +BooleanProcessor::draw_edge(int icol, int iedge) { + int i1, i2; + float p1[3], p2[3]; + + i1 = edges[iedge].i1; + p1[0] = nodes[i1].v.x(); + p1[1] = nodes[i1].v.y(); + p1[2] = nodes[i1].v.z(); + IHWTON(p1,p1); + i2 = edges[iedge].i2; + p2[0] = nodes[i2].v.x(); + p2[1] = nodes[i2].v.y(); + p2[2] = nodes[i2].v.z(); + IHWTON(p2,p2); + IHZLIN(icol,p1[0],p1[1],p1[2], p2[0],p2[1],p2[2]); +} + +//-------------------------------------------------------------------- +void +BooleanProcessor::draw_contour(int i1col, int i2col, int ihead) { + int iedge, icol; + iedge = ihead; + while (iedge > 0) { + icol = (edges[iedge].ivis > 0) ? i1col : i2col; + draw_edge(icol, iedge); + iedge = edges[iedge].inext; + } + + IHZTOX(0,100,100); + ixupdwi(0); + + int i; + std::cin >> i; +} + +//-------------------------------------------------------------------- +void +BooleanProcessor::print_face(int iface) { + G4cout.precision(3); + G4cout << "\n====== Face N " << iface << G4endl; + G4cout << "iedges[4] = " + << faces[iface].iedges[0] << ", " + << faces[iface].iedges[1] << ", " + << faces[iface].iedges[2] << ", " + << faces[iface].iedges[3] << G4endl; + G4cout << "rmin[3] = " + << faces[iface].rmin[0] << ", " + << faces[iface].rmin[1] << ", " + << faces[iface].rmin[2] << G4endl; + G4cout << "rmax[3] = " + << faces[iface].rmax[0] << ", " + << faces[iface].rmax[1] << ", " + << faces[iface].rmax[2] << G4endl; + G4cout << "iprev,inext = " + << faces[iface].iprev << ", " + << faces[iface].inext << G4endl; + G4cout << "iold = " << faces[iface].iold << G4endl; + for(int i = faces[iface].iold; i != 0;) { + print_edge(i); + i = edges[abs(i)].inext; + } + + G4cout << "inew = "; + switch (faces[iface].inew) { + case UNKNOWN_FACE: + G4cout << "UNKNOWN_FACE" << G4endl; + break; + case ORIGINAL_FACE: + G4cout << "ORIGINAL_FACE" << G4endl; + break; + case NEW_FACE: + G4cout << "NEW_FACE" << G4endl; + break; + case UNSUITABLE_FACE: + G4cout << "UNSUITABLE_FACE" << G4endl; + break; + case DEFECTIVE_FACE: + G4cout << "DEFECTIVE_FACE" << G4endl; + break; + default: + G4cout << faces[iface].inew << G4endl; + for(int k = faces[iface].inew; k != 0;) { + print_edge(k); + k = edges[abs(k)].inext; + } + } +} + +//-------------------------------------------------------------------- +void +BooleanProcessor::print_edge(int iedge) { + G4cout << "==== Edge N " << iedge << G4endl; + int i = std::abs(iedge); + int i1 = edges[i].i1; + int i2 = edges[i].i2; + G4cout << "node[" << i1 << "] = " + << nodes[i1].v.x() << ", " + << nodes[i1].v.y() << ", " + << nodes[i1].v.z() << G4endl; + + G4cout << "node[" << i2 << "] = " + << nodes[i2].v.x() << ", " + << nodes[i2].v.y() << ", " + << nodes[i2].v.z() << G4endl; + + G4cout << "iface1,iface2,ivis,inext = " + << edges[i].iface1 << ", " + << edges[i].iface2 << ", " + << edges[i].ivis << ", " + << edges[i].inext << G4endl; +} +*/ + +void BooleanProcessor::dump() {//G.Barrand + unsigned int number = nodes.size(); + G4cout << "nodes : " << number << G4endl; + for(unsigned int index=0;index 0) { + G4cout << iface; + iface = faces[iface].inext; + if (iface) G4cout << ","; + } + G4cout << "." << std::endl; +} + diff --git a/src/G4.10.04.p02fixes/G4CoupledTransportation.cc b/src/G4.10.04.p02fixes/G4CoupledTransportation.cc new file mode 100644 index 0000000..bbaae98 --- /dev/null +++ b/src/G4.10.04.p02fixes/G4CoupledTransportation.cc @@ -0,0 +1,1027 @@ +// +// ******************************************************************** +// * 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: G4CoupledTransportation.cc 105913 2017-08-28 08:39:12Z gcosmo $ +// +// ------------------------------------------------------------ +// GEANT 4 class implementation +// ======================================================================= +// Modified: +// 10 Jan 2015, M.Kelsey: Use G4DynamicParticle mass, NOT PDGMass +// 13 May 2006, J. Apostolakis: Revised for parallel navigation (PathFinder) +// 19 Jan 2006, P.MoraDeFreitas: Fix for suspended tracks (StartTracking) +// 11 Aug 2004, M.Asai: Add G4VSensitiveDetector* for updating stepPoint. +// 21 June 2003, J.Apostolakis: Calling field manager with +// track, to enable it to configure its accuracy +// 13 May 2003, J.Apostolakis: Zero field areas now taken into +// account correclty in all cases (thanks to W Pokorski). +// 29 June 2001, J.Apostolakis, D.Cote-Ahern, P.Gumplinger: +// correction for spin tracking +// 20 Febr 2001, J.Apostolakis: update for new FieldTrack +// 22 Sept 2000, V.Grichine: update of Kinetic Energy +// Created: 19 March 1997, J. Apostolakis +// ======================================================================= + +#include "G4CoupledTransportation.hh" + +#include "G4PhysicalConstants.hh" +#include "G4SystemOfUnits.hh" +#include "G4TransportationProcessType.hh" +#include "G4ProductionCutsTable.hh" +#include "G4ParticleTable.hh" +#include "G4ChordFinder.hh" +#include "G4Field.hh" +#include "G4FieldTrack.hh" +#include "G4FieldManagerStore.hh" + +class G4VSensitiveDetector; + +G4bool G4CoupledTransportation::fSignifyStepInAnyVolume= false; +// This mode must apply to all threads + +G4bool G4CoupledTransportation::fUseMagneticMoment=false; +////////////////////////////////////////////////////////////////////////// +// +// Constructor + +G4CoupledTransportation::G4CoupledTransportation( G4int verbosity ) + : G4VProcess( G4String("CoupledTransportation"), fTransportation ), + fTransportEndPosition(0.0, 0.0, 0.0), + fTransportEndMomentumDir(0.0, 0.0, 0.0), + fTransportEndKineticEnergy(0.0), + fTransportEndSpin(0.0, 0.0, 0.0), // fTransportEndPolarization(0.0, 0.0, 0.0), + fMomentumChanged(false), + fEndGlobalTimeComputed(false), + fCandidateEndGlobalTime(0.0), + fParticleIsLooping( false ), + fNewTrack( true ), + fPreviousSftOrigin( 0.,0.,0. ), + fPreviousMassSafety( 0.0 ), + fPreviousFullSafety( 0.0 ), + fMassGeometryLimitedStep( false ), + fAnyGeometryLimitedStep( false ), + fEndpointDistance( -1.0 ), + fThreshold_Warning_Energy( 100 * MeV ), + fThreshold_Important_Energy( 250 * MeV ), + fThresholdTrials( 10 ), + fNoLooperTrials( 0 ), + fSumEnergyKilled( 0.0 ), fMaxEnergyKilled( 0.0 ), + fFirstStepInMassVolume( true ), + fFirstStepInAnyVolume( true ) +{ + // set Process Sub Type + SetProcessSubType(static_cast(COUPLED_TRANSPORTATION)); + SetVerboseLevel(verbosity); + + G4TransportationManager* transportMgr ; + + transportMgr = G4TransportationManager::GetTransportationManager() ; + + fMassNavigator = transportMgr->GetNavigatorForTracking() ; + fFieldPropagator = transportMgr->GetPropagatorInField() ; + // fGlobalFieldMgr = transportMgr->GetFieldManager() ; + fNavigatorId= transportMgr->ActivateNavigator( fMassNavigator ); + if( verboseLevel > 0 ) + { + G4cout << " G4CoupledTransportation constructor: ----- " << G4endl; + G4cout << " Verbose level is " << verboseLevel << G4endl; + G4cout << " Navigator Id obtained in G4CoupledTransportation constructor " + << fNavigatorId << G4endl; + G4cout << " Reports First/Last in " + << (fSignifyStepInAnyVolume ? " any " : " mass " ) << " geometry " << G4endl; + } + fPathFinder= G4PathFinder::GetInstance(); + fpSafetyHelper = transportMgr->GetSafetyHelper(); // New + + // Following assignment is to fix small memory leak from simple use of 'new' + static G4ThreadLocal G4TouchableHandle* pNullTouchableHandle = 0; + if ( !pNullTouchableHandle) { pNullTouchableHandle = new G4TouchableHandle; } + fCurrentTouchableHandle = *pNullTouchableHandle; + // Points to (G4VTouchable*) 0 + + G4FieldManager *globalFieldMgr= transportMgr->GetFieldManager(); + fGlobalFieldExists= globalFieldMgr ? globalFieldMgr->GetDetectorField() : 0 ; +} + +////////////////////////////////////////////////////////////////////////// + +G4CoupledTransportation::~G4CoupledTransportation() +{ + // fCurrentTouchableHandle is a data member - no deletion required + + if( (verboseLevel > 0) || (fSumEnergyKilled > 0.0 ) ) + { + G4cout << " G4CoupledTransportation: Statistics for looping particles " << G4endl; + G4cout << " Sum of energy of loopers killed: " << fSumEnergyKilled << G4endl; + G4cout << " Max energy of loopers killed: " << fMaxEnergyKilled << G4endl; + } +} + +////////////////////////////////////////////////////////////////////////// +// +// Responsibilities: +// Find whether the geometry limits the Step, and to what length +// Calculate the new value of the safety and return it. +// Store the final time, position and momentum. + +G4double G4CoupledTransportation:: +AlongStepGetPhysicalInteractionLength( const G4Track& track, + G4double, // previousStepSize + G4double currentMinimumStep, + G4double& proposedSafetyForStart, + G4GPILSelection* selection ) +{ + G4double geometryStepLength; + G4double startMassSafety= 0.0; // estimated safety for start point (mass geometry) + G4double startFullSafety= 0.0; // estimated safety for start point (all geometries) + G4double safetyProposal= -1.0; // local copy of proposal + + G4ThreeVector EndUnitMomentum ; + G4double lengthAlongCurve=0.0 ; + + fParticleIsLooping = false ; + + // Initial actions moved to StartTrack() + // -------------------------------------- + // Note: in case another process changes touchable handle + // it will be necessary to add here (for all steps) + // fCurrentTouchableHandle = aTrack->GetTouchableHandle(); + + // GPILSelection is set to defaule value of CandidateForSelection + // It is a return value + // + *selection = CandidateForSelection ; + + fFirstStepInMassVolume = fNewTrack | fMassGeometryLimitedStep ; + fFirstStepInAnyVolume = fNewTrack | fAnyGeometryLimitedStep ; + +#ifdef G4DEBUG_TRANSPORT + G4cout << " CoupledTransport::AlongStep GPIL: " + << " 1st-step: any= " < called in volume " + << currentVolume->GetName() << G4endl; + } +#endif + // G4double theTime = track.GetGlobalTime() ; + + // The Step Point safety can be limited by other geometries and/or the + // assumptions of any process - it's not always the geometrical safety. + // We calculate the starting point's isotropic safety here. + // + G4ThreeVector OriginShift = startPosition - fPreviousSftOrigin ; + G4double MagSqShift = OriginShift.mag2() ; + startMassSafety = 0.0; + startFullSafety= 0.0; + + // Recall that FullSafety <= MassSafety + // Original: if( MagSqShift < sqr(fPreviousMassSafety) ) { + if( MagSqShift < sqr(fPreviousFullSafety) ) // Revision proposed by Alex H, 2 Oct 07 + { + G4double mag_shift= std::sqrt(MagSqShift); + startMassSafety = std::max( (fPreviousMassSafety - mag_shift), 0.0); + startFullSafety = std::max( (fPreviousFullSafety - mag_shift), 0.0); + // Need to be consistent between full safety with Mass safety + // in order reproduce results in simple case --> use same calculation method + + // Only compute full safety if massSafety > 0. Else it remains 0 + // startFullSafety = fPathFinder->ComputeSafety( startPosition ); + } + + // Is the particle charged or has it a magnetic moment? + // + G4double particleCharge = pParticle->GetCharge() ; + G4double magneticMoment = pParticle->GetMagneticMoment() ; + G4double restMass = pParticle->GetMass() ; + + fMassGeometryLimitedStep = false ; // Set default - alex + fAnyGeometryLimitedStep = false; + + // fEndGlobalTimeComputed = false ; + + // There is no need to locate the current volume. It is Done elsewhere: + // On track construction + // By the tracking, after all AlongStepDoIts, in "Relocation" + + // Check if the particle has a force, EM or gravitational, exerted on it + // + G4FieldManager* fieldMgr=0; + G4bool fieldExertsForce = false ; + + G4bool gravityOn = false; + const G4Field* ptrField= 0; + + fieldMgr = fFieldPropagator->FindAndSetFieldManager( track.GetVolume() ); + if( fieldMgr != 0 ) + { + // Message the field Manager, to configure it for this track + fieldMgr->ConfigureForTrack( &track ); + // Here it can transition from a null field-ptr to a finite field + + // If the field manager has no field ptr, the field is zero + // by definition ( = there is no field ! ) + ptrField= fieldMgr->GetDetectorField(); + + if( ptrField != 0) + { + gravityOn= ptrField->IsGravityActive(); + if( (particleCharge != 0.0) + || (fUseMagneticMoment && (magneticMoment != 0.0) ) + || (gravityOn && (restMass != 0.0)) + ) + { + fieldExertsForce = true; + } + } + } + G4double momentumMagnitude = pParticle->GetTotalMomentum() ; + + if( fieldExertsForce ) + { + auto equationOfMotion= fFieldPropagator->GetCurrentEquationOfMotion(); + + G4ChargeState chargeState(particleCharge, // The charge can change (dynamic) + magneticMoment, + pParticleDef->GetPDGSpin() ); + // For insurance, could set it again + // chargeState.SetPDGSpin( pParticleDef->GetPDGSpin() ); // Newly/provisionally in same object + + if( equationOfMotion ) + { + equationOfMotion->SetChargeMomentumMass( chargeState, + momentumMagnitude, + restMass ); + } +#ifdef G4DEBUG_TRANSPORT + else + { + G4cerr << " ERROR in G4CoupledTransportation> " + << "Cannot find valid Equation of motion: " << G4endl; + << " Unable to pass Charge, Momentum and Mass " << G4endl; + } +#endif + } + + G4ThreeVector polarizationVec = track.GetPolarization() ; + G4FieldTrack aFieldTrack = G4FieldTrack( startPosition, + track.GetGlobalTime(), // Lab. + // track.GetProperTime(), // Particle rest frame + track.GetMomentumDirection(), + track.GetKineticEnergy(), + restMass, + particleCharge, + polarizationVec, + pParticleDef->GetPDGMagneticMoment(), + 0.0, // Length along track + pParticleDef->GetPDGSpin() + ) ; + G4int stepNo= track.GetCurrentStepNumber(); + + ELimited limitedStep; + G4FieldTrack endTrackState('a'); // Default values + + fMassGeometryLimitedStep = false ; // default + fAnyGeometryLimitedStep = false ; + if( currentMinimumStep > 0 ) + { + G4double newMassSafety= 0.0; // temp. for recalculation + + // Do the Transport in the field (non recti-linear) + // + lengthAlongCurve = fPathFinder->ComputeStep( aFieldTrack, + currentMinimumStep, + fNavigatorId, + stepNo, + newMassSafety, + limitedStep, + endTrackState, + currentVolume ) ; + // G4cout << " PathFinder ComputeStep returns " << lengthAlongCurve << G4endl; + + G4double newFullSafety= fPathFinder->GetCurrentSafety(); + // this was estimated already in step above + // G4double newFullStep= fPathFinder->GetMinimumStep(); + + if( limitedStep == kUnique || limitedStep == kSharedTransport ) + { + fMassGeometryLimitedStep = true ; + } + + fAnyGeometryLimitedStep = (fPathFinder->GetNumberGeometriesLimitingStep() != 0) ; + +#ifdef G4DEBUG_TRANSPORT + if( fMassGeometryLimitedStep && !fAnyGeometryLimitedStep ) + { + std::ostringstream message; + message << " ERROR in determining geometries limiting the step" << G4endl; + message << " Limiting: mass=" << fMassGeometryLimitedStep + << " any= " << fAnyGeometryLimitedStep << G4endl; + message << "Incompatible conditions - by which geometries was it limited ?"<SetCurrentSafety( newFullSafety, startPosition); + +#ifdef G4DEBUG_TRANSPORT + if( verboseLevel > 1 ) + { + G4cout << "G4Transport:CompStep> " + << " called the pathfinder for a new step at " << startPosition + << " and obtained step = " << lengthAlongCurve << G4endl; + G4cout << " New safety (preStep) = " << newMassSafety + << " versus precalculated = " << startMassSafety << G4endl; + } +#endif + + // Store as best estimate value + startMassSafety = newMassSafety ; + startFullSafety = newFullSafety ; + + // Get the End-Position and End-Momentum (Dir-ection) + fTransportEndPosition = endTrackState.GetPosition() ; + fTransportEndKineticEnergy = endTrackState.GetKineticEnergy() ; + } + else + { + geometryStepLength = lengthAlongCurve= 0.0 ; + fMomentumChanged = false ; + // fMassGeometryLimitedStep = false ; // --- ??? + // fAnyGeometryLimitedStep = true; + fTransportEndMomentumDir = track.GetMomentumDirection(); + fTransportEndKineticEnergy = track.GetKineticEnergy(); + + fTransportEndPosition = startPosition; + + endTrackState= aFieldTrack; // Ensures that time is updated + + // If the step length requested is 0, and we are on a boundary + // then a boundary will also limit the step. + if( startMassSafety == 0.0 ) + { + fMassGeometryLimitedStep = true ; + fAnyGeometryLimitedStep = true; + } + // TODO: Add explicit logical status for being at a boundary + } + // G4FieldTrack aTrackState(endTrackState); + + if( !fieldExertsForce ) + { + fParticleIsLooping = false ; + fMomentumChanged = false ; + fEndGlobalTimeComputed = false ; + // G4cout << " global time is false " << G4endl; + } + else + { + +#ifdef G4DEBUG_TRANSPORT + if( verboseLevel > 1 ) + { + G4cout << " G4CT::CS End Position = " << fTransportEndPosition << G4endl; + G4cout << " G4CT::CS End Direction = " << fTransportEndMomentumDir << G4endl; + } +#endif + if( fFieldPropagator->GetCurrentFieldManager()->DoesFieldChangeEnergy() ) + { + // If the field can change energy, then the time must be integrated + // - so this should have been updated + // + fCandidateEndGlobalTime = endTrackState.GetLabTimeOfFlight(); + fEndGlobalTimeComputed = true; + + // was ( fCandidateEndGlobalTime != track.GetGlobalTime() ); + // a cleaner way is to have FieldTrack knowing whether time is updated. + } + else + { + // The energy should be unchanged by field transport, + // - so the time changed will be calculated elsewhere + // + fEndGlobalTimeComputed = false; + + // Check that the integration preserved the energy + // - and if not correct this! + G4double startEnergy= track.GetKineticEnergy(); + G4double endEnergy= fTransportEndKineticEnergy; + + static G4ThreadLocal G4int no_inexact_steps=0; // , no_large_ediff; + G4double absEdiff = std::fabs(startEnergy- endEnergy); + if( absEdiff > perMillion * endEnergy ) + { + no_inexact_steps++; + // Possible statistics keeping here ... + } +#ifdef G4VERBOSE + if( (verboseLevel > 1) && ( absEdiff > perThousand * endEnergy) ) + { + ReportInexactEnergy(startEnergy, endEnergy); + } // end of if (verboseLevel) +#endif + // Correct the energy for fields that conserve it + // This - hides the integration error + // - but gives a better physical answer + fTransportEndKineticEnergy= track.GetKineticEnergy(); + } + } + + fEndpointDistance = (fTransportEndPosition - startPosition).mag() ; + fParticleIsLooping = fFieldPropagator->IsParticleLooping() ; + + fTransportEndSpin = endTrackState.GetSpin(); + + // Calculate the safety + safetyProposal= startFullSafety; // used to be startMassSafety + // Changed to accomodate processes that cannot update the safety -- JA 22 Nov 06 + + // Update safety for the end-point, if becomes negative at the end-point. + + if( (startFullSafety < fEndpointDistance ) + && ( particleCharge != 0.0 ) ) // Only needed to prepare for Mult Scat. + // && !fAnyGeometryLimitedStep ) // To-Try: No safety update if at a boundary + { + G4double endFullSafety = + fPathFinder->ComputeSafety( fTransportEndPosition); + // Expected mission -- only mass geometry's safety + // fMassNavigator->ComputeSafety( fTransportEndPosition) ; + // Yet discrete processes only have poststep -- and this cannot + // currently revise the safety + // ==> so we use the all-geometry safety as a precaution + + fpSafetyHelper->SetCurrentSafety( endFullSafety, fTransportEndPosition); + // Pushing safety to Helper avoids recalculation at this point + + G4ThreeVector centerPt= G4ThreeVector(0.0, 0.0, 0.0); // Used for return value + G4double endMassSafety= fPathFinder->ObtainSafety( fNavigatorId, centerPt); + // Retrieves the mass value from PathFinder (it calculated it) + + fPreviousMassSafety = endMassSafety ; + fPreviousFullSafety = endFullSafety; + fPreviousSftOrigin = fTransportEndPosition ; + + // The convention (Stepping Manager's) is safety from the start point + // + safetyProposal = endFullSafety + fEndpointDistance; + // --> was endMassSafety + // Changed to accomodate processes that cannot update the safety -- JA 22 Nov 06 + + // #define G4DEBUG_TRANSPORT 1 + +#ifdef G4DEBUG_TRANSPORT + G4int prec= G4cout.precision(12) ; + G4cout << "***Transportation::AlongStepGPIL ** " << G4endl ; + G4cout << " Revised Safety at endpoint " << fTransportEndPosition + << " give safety values: Mass= " << endMassSafety + << " All= " << endFullSafety << G4endl ; + G4cout << " Adding endpoint distance " << fEndpointDistance + << " to obtain pseudo-safety= " << safetyProposal << G4endl ; + G4cout.precision(prec); + } + else + { + G4int prec= G4cout.precision(12) ; + G4cout << "***Transportation::AlongStepGPIL ** " << G4endl ; + G4cout << " Quick Safety estimate at endpoint " << fTransportEndPosition + << " gives safety endpoint value = " << startFullSafety - fEndpointDistance + << " using start-point value " << startFullSafety + << " and endpointDistance " << fEndpointDistance << G4endl; + G4cout.precision(prec); +#endif + } + + proposedSafetyForStart= safetyProposal; + fParticleChange.ProposeTrueStepLength(geometryStepLength) ; + + return geometryStepLength ; +} + +////////////////////////////////////////////////////////////////////////// + +G4VParticleChange* +G4CoupledTransportation::AlongStepDoIt( const G4Track& track, + const G4Step& stepData ) +{ + static G4ThreadLocal G4int noCalls=0; + noCalls++; + + fParticleChange.Initialize(track) ; + // sets all its members to the value of corresponding members in G4Track + + // Code specific for Transport + // + fParticleChange.ProposePosition(fTransportEndPosition) ; + // G4cout << " G4CoupledTransportation::AlongStepDoIt" + // << " proposes position = " << fTransportEndPosition + // << " and end momentum direction = " << fTransportEndMomentumDir << G4endl; + fParticleChange.ProposeMomentumDirection(fTransportEndMomentumDir) ; + fParticleChange.ProposeEnergy(fTransportEndKineticEnergy) ; + fParticleChange.SetMomentumChanged(fMomentumChanged) ; + + fParticleChange.ProposePolarization(fTransportEndSpin); + + G4double deltaTime = 0.0 ; + + // Calculate Lab Time of Flight (ONLY if field Equations used it!) + // G4double endTime = fCandidateEndGlobalTime; + // G4double delta_time = endTime - startTime; + + G4double startTime = track.GetGlobalTime() ; + + if (!fEndGlobalTimeComputed) + { + G4double finalInverseVel= DBL_MAX, initialInverseVel=DBL_MAX; + + // The time was not integrated .. make the best estimate possible + // + G4double finalVelocity = track.GetVelocity() ; + if( finalVelocity > 0.0 ) { finalInverseVel= 1.0 / finalVelocity; } + G4double initialVelocity = stepData.GetPreStepPoint()->GetVelocity() ; + if( initialVelocity > 0.0 ) { initialInverseVel= 1.0 / initialVelocity; } + G4double stepLength = track.GetStepLength() ; + + if (finalVelocity > 0.0) + { + // deltaTime = stepLength/finalVelocity ; + G4double meanInverseVelocity = 0.5 * ( initialInverseVel + finalInverseVel ); + deltaTime = stepLength * meanInverseVelocity ; + // G4cout << " dt = s * mean(1/v) , with " << " s = " << stepLength + // << " mean(1/v)= " << meanInverseVelocity << G4endl; + } + else + { + deltaTime = stepLength * initialInverseVel ; + // G4cout << " dt = s / initV " << " s = " << stepLength + // << " 1 / initV= " << initialInverseVel << G4endl; + } // Could do with better estimate for final step (finalVelocity = 0) ? + + fCandidateEndGlobalTime = startTime + deltaTime ; + fParticleChange.ProposeLocalTime( track.GetLocalTime() + deltaTime) ; + + // G4cout << " Calculated global time from start = " << startTime << " and " + // << " delta time = " << deltaTime << G4endl; + } + else + { + deltaTime = fCandidateEndGlobalTime - startTime ; + fParticleChange.ProposeGlobalTime( fCandidateEndGlobalTime ) ; + // G4cout << " Calculated global time from candidate end time = " + // << fCandidateEndGlobalTime << " and start time = " << startTime << G4endl; + } + + // G4cout << " G4CoupledTransportation::AlongStepDoIt " + // << " flag whether computed time = " << fEndGlobalTimeComputed << " and " + // << " is proposes end time " << fCandidateEndGlobalTime << G4endl; + + // Now Correct by Lorentz factor to get "proper" deltaTime + + G4double restMass = track.GetDynamicParticle()->GetMass() ; + G4double deltaProperTime = deltaTime*( restMass/track.GetTotalEnergy() ) ; + + fParticleChange.ProposeProperTime(track.GetProperTime() + deltaProperTime) ; + //fParticleChange. ProposeTrueStepLength( track.GetStepLength() ) ; + + // If the particle is caught looping or is stuck (in very difficult + // boundaries) in a magnetic field (doing many steps) + // THEN this kills it ... + // + if ( fParticleIsLooping ) + { + G4double endEnergy= fTransportEndKineticEnergy; + + if( (endEnergy < fThreshold_Important_Energy) + || (fNoLooperTrials >= fThresholdTrials ) ) + { + // Kill the looping particle + // + fParticleChange.ProposeTrackStatus( fStopAndKill ) ; + + // 'Bare' statistics + fSumEnergyKilled += endEnergy; + if( endEnergy > fMaxEnergyKilled) { fMaxEnergyKilled= endEnergy; } + +#ifdef G4VERBOSE + if((verboseLevel > 1) && ( endEnergy > fThreshold_Warning_Energy )) + { + G4cout << " G4CoupledTransportation is killing track that is looping or stuck " << G4endl + << " This track has " << track.GetKineticEnergy() / MeV + << " MeV energy." << G4endl; + } + if( verboseLevel > 0 ) + { + G4cout << " Steps by this track: " << track.GetCurrentStepNumber() << G4endl; + } +#endif + fNoLooperTrials=0; + } + else + { + fNoLooperTrials ++; +#ifdef G4VERBOSE + if( (verboseLevel > 2) ) + { + G4cout << " ** G4CoupledTransportation::AlongStepDoIt(): Particle looping - " << G4endl + << " Number of consecutive problem step (this track) = " << fNoLooperTrials << G4endl + << " Steps by this track: " << track.GetCurrentStepNumber() << G4endl + << " Total no of calls to this method (all tracks) = " << noCalls << G4endl; + } +#endif + } + } + else + { + fNoLooperTrials=0; + } + + // Another (sometimes better way) is to use a user-limit maximum Step size + // to alleviate this problem .. + + // Add smooth curved trajectories to particle-change + // + // fParticleChange.SetPointerToVectorOfAuxiliaryPoints + // (fFieldPropagator->GimmeTrajectoryVectorAndForgetIt() ); + + return &fParticleChange ; +} + +////////////////////////////////////////////////////////////////////////// +// +// This ensures that the PostStep action is always called, +// so that it can do the relocation if it is needed. +// + +G4double G4CoupledTransportation:: +PostStepGetPhysicalInteractionLength( const G4Track&, + G4double, // previousStepSize + G4ForceCondition* pForceCond ) +{ + // Must act as PostStep action -- to relocate particle + *pForceCond = Forced ; + return DBL_MAX ; +} + +void G4CoupledTransportation:: +ReportMove( G4ThreeVector OldVector, G4ThreeVector NewVector, const G4String& Quantity ) +{ + G4ThreeVector moveVec = ( NewVector - OldVector ); + + G4cerr << G4endl + << "**************************************************************" << G4endl; + G4cerr << "Endpoint has moved between value expected from TransportEndPosition " + << " and value from Track in PostStepDoIt. " << G4endl + << "Change of " << Quantity << " is " << moveVec.mag() / mm << " mm long, " + << " and its vector is " << (1.0/mm) * moveVec << " mm " << G4endl + << "Endpoint of ComputeStep was " << OldVector + << " and current position to locate is " << NewVector << G4endl; +} + +///////////////////////////////////////////////////////////////////////////// + +G4VParticleChange* G4CoupledTransportation::PostStepDoIt( const G4Track& track, + const G4Step& ) +{ + G4TouchableHandle retCurrentTouchable ; // The one to return + + // Initialize ParticleChange (by setting all its members equal + // to corresponding members in G4Track) + // fParticleChange.Initialize(track) ; // To initialise TouchableChange + + fParticleChange.ProposeTrackStatus(track.GetTrackStatus()) ; + + // G4cout << " CoupledTransportation::PostStepDoIt> particleChange: addr= " << &fParticleChange; + + if( fSignifyStepInAnyVolume ){ + fParticleChange.ProposeFirstStepInVolume( fFirstStepInAnyVolume ); + // G4cout << " First Step In Any Volume = " << fFirstStepInAnyVolume << G4endl; + }else{ + fParticleChange.ProposeFirstStepInVolume( fFirstStepInMassVolume ); + // G4cout << " First Step In Mass Volume = " << fFirstStepInAnyVolume << G4endl; + } + + // Check that the end position and direction are preserved + // since call to AlongStepDoIt + +#ifdef G4DEBUG_TRANSPORT + if( ( verboseLevel > 0 ) + && ((fTransportEndPosition - track.GetPosition()).mag2() >= 1.0e-16) ) + { + ReportMove( track.GetPosition(), fTransportEndPosition, "End of Step Position" ); + G4cerr << " Problem in G4CoupledTransportation::PostStepDoIt " << G4endl; + } + + // If the Step was determined by the volume boundary, relocate the particle + // The pathFinder will know that the geometry limited the step (!?) + + if( verboseLevel > 0 ) + { + G4cout << " Calling PathFinder::Locate() from " + << " G4CoupledTransportation::PostStepDoIt " << G4endl; + G4cout << " fAnyGeometryLimitedStep is " << fAnyGeometryLimitedStep << G4endl; + + } +#endif + + if(fAnyGeometryLimitedStep) + { + fPathFinder->Locate( track.GetPosition(), + track.GetMomentumDirection(), + true); + + // fCurrentTouchable will now become the previous touchable, + // and what was the previous will be freed. + // (Needed because the preStepPoint can point to the previous touchable) + + fCurrentTouchableHandle= + fPathFinder->CreateTouchableHandle( fNavigatorId ); + +#ifdef G4DEBUG_TRANSPORT + if( verboseLevel > 0 ) + { + G4cout << "G4CoupledTransportation::PostStepDoIt --- fNavigatorId = " + << fNavigatorId << G4endl; + } + if( verboseLevel > 1 ) + { + G4VPhysicalVolume* vol= fCurrentTouchableHandle->GetVolume(); + G4cout << "CHECK !!!!!!!!!!! fCurrentTouchableHandle->GetVolume() = " << vol; + if( vol ) { G4cout << "Name=" << vol->GetName(); } + G4cout << G4endl; + } +#endif + + // Check whether the particle is out of the world volume + // If so it has exited and must be killed. + // + if( fCurrentTouchableHandle->GetVolume() == 0 ) + { + fParticleChange.ProposeTrackStatus( fStopAndKill ) ; + } + retCurrentTouchable = fCurrentTouchableHandle ; + // fParticleChange.SetTouchableHandle( fCurrentTouchableHandle ) ; + } + else // fAnyGeometryLimitedStep is false + { +#ifdef G4DEBUG_TRANSPORT + if( verboseLevel > 1 ) + { + G4cout << "G4CoupledTransportation::PostStepDoIt -- " + << " fAnyGeometryLimitedStep = " << fAnyGeometryLimitedStep + << " must be false " << G4endl; + } +#endif + // This serves only to move each of the Navigator's location + // + // fLinearNavigator->LocateGlobalPointWithinVolume( track.GetPosition() ) ; + + // G4cout << "G4CoupledTransportation calling PathFinder::ReLocate() " << G4endl; + fPathFinder->ReLocate( track.GetPosition() ); + // track.GetMomentumDirection() ); + + // Keep the value of the track's current Touchable is retained, + // and use it to overwrite the (unset) one in particle change. + // Expect this must be fCurrentTouchable too + // - could it be different, eg at the start of a step ? + // + retCurrentTouchable = track.GetTouchableHandle() ; + // fParticleChange.SetTouchableHandle( track.GetTouchableHandle() ) ; + } // endif ( fAnyGeometryLimitedStep ) + +#ifdef G4DEBUG_NAVIGATION + G4cout << " CoupledTransport::AlongStep GPIL: " + << " last-step: any= " << fAnyGeometryLimitedStep << " . ..... x . " + << " mass= " << fMassGeometryLimitedStep + << G4endl; +#endif + + if( fSignifyStepInAnyVolume ) + fParticleChange.ProposeLastStepInVolume(fAnyGeometryLimitedStep); + else + fParticleChange.ProposeLastStepInVolume(fMassGeometryLimitedStep); + + const G4VPhysicalVolume* pNewVol = retCurrentTouchable->GetVolume() ; + const G4Material* pNewMaterial = 0 ; + const G4VSensitiveDetector* pNewSensitiveDetector = 0 ; + + if( pNewVol != 0 ) + { + pNewMaterial= pNewVol->GetLogicalVolume()->GetMaterial(); + pNewSensitiveDetector= pNewVol->GetLogicalVolume()->GetSensitiveDetector(); + } + + // ( const_cast pNewMaterial ) ; + // ( const_cast pNewSensitiveDetector) ; + + fParticleChange.SetMaterialInTouchable( (G4Material *) pNewMaterial ) ; + fParticleChange.SetSensitiveDetectorInTouchable( (G4VSensitiveDetector *) pNewSensitiveDetector ) ; + // "temporarily" until Get/Set Material of ParticleChange, + // and StepPoint can be made const. + + const G4MaterialCutsCouple* pNewMaterialCutsCouple = 0; + if( pNewVol != 0 ) + { + pNewMaterialCutsCouple=pNewVol->GetLogicalVolume()->GetMaterialCutsCouple(); + if( pNewMaterialCutsCouple!=0 + && pNewMaterialCutsCouple->GetMaterial()!=pNewMaterial ) + { + // for parametrized volume + // + pNewMaterialCutsCouple = + G4ProductionCutsTable::GetProductionCutsTable() + ->GetMaterialCutsCouple(pNewMaterial, + pNewMaterialCutsCouple->GetProductionCuts()); + } + } + fParticleChange.SetMaterialCutsCoupleInTouchable( pNewMaterialCutsCouple ); + + // Must always set the touchable in ParticleChange, whether relocated or not + fParticleChange.SetTouchableHandle(retCurrentTouchable) ; + + return &fParticleChange ; +} + +// New method takes over the responsibility to reset the state of +// G4CoupledTransportation object: +// - at the start of a new track, and +// - on the resumption of a suspended track. + +void +G4CoupledTransportation::StartTracking(G4Track* aTrack) +{ + + G4TransportationManager* transportMgr = + G4TransportationManager::GetTransportationManager(); + + // G4VProcess::StartTracking(aTrack); + fNewTrack= true; + + // The 'initialising' actions + // once taken in AlongStepGPIL -- if ( track.GetCurrentStepNumber()==1 ) + + // fStartedNewTrack= true; + + fMassNavigator = transportMgr->GetNavigatorForTracking() ; + fNavigatorId= transportMgr->ActivateNavigator( fMassNavigator ); // Confirm it! + + // if( verboseLevel > 1 ){ + // G4cout << " Navigator Id obtained in StartTracking " << fNavigatorId << G4endl; + // } + G4ThreeVector position = aTrack->GetPosition(); + G4ThreeVector direction = aTrack->GetMomentumDirection(); + + // if( verboseLevel > 1 ){ + // G4cout << " Calling PathFinder::PrepareNewTrack from " + // << " G4CoupledTransportation::StartTracking -- which calls Locate()" << G4endl; + // } + fPathFinder->PrepareNewTrack( position, direction); + // This implies a call to fPathFinder->Locate( position, direction ); + + // Global field, if any, must exist before tracking is started + fGlobalFieldExists= DoesGlobalFieldExist(); + // reset safety value and center + // + fPreviousMassSafety = 0.0 ; + fPreviousFullSafety = 0.0 ; + fPreviousSftOrigin = G4ThreeVector(0.,0.,0.) ; + + // reset looping counter -- for motion in field + fNoLooperTrials= 0; + // Must clear this state .. else it depends on last track's value + // --> a better solution would set this from state of suspended track TODO ? + // Was if( aTrack->GetCurrentStepNumber()==1 ) { .. } + + // ChordFinder reset internal state + // + if( fFieldPropagator ) + { + fFieldPropagator->ClearPropagatorState(); + // Resets safety values, in case of overlaps. + + G4ChordFinder* chordF= fFieldPropagator->GetChordFinder(); + if( chordF ) { chordF->ResetStepEstimate(); } + } + + // Clear the chord finders of all fields (ie managers) derived objects + // + G4FieldManagerStore* fieldMgrStore = G4FieldManagerStore::GetInstance(); + fieldMgrStore->ClearAllChordFindersState(); + +#ifdef G4DEBUG_TRANSPORT + if( verboseLevel > 1 ) + { + G4cout << " Returning touchable handle " << fCurrentTouchableHandle << G4endl; + } +#endif + + // Update the current touchable handle (from the track's) + // + fCurrentTouchableHandle = aTrack->GetTouchableHandle(); +} + +void +G4CoupledTransportation::EndTracking() +{ + G4TransportationManager::GetTransportationManager()->InactivateAll(); + fPathFinder->EndTrack(); // Resets TransportationManager to use ordinary Navigator +} + +void +G4CoupledTransportation:: +ReportInexactEnergy(G4double startEnergy, G4double endEnergy) +{ + static G4ThreadLocal G4int no_warnings= 0, warnModulo=1, moduloFactor= 10, no_large_ediff= 0; + + if( std::fabs(startEnergy- endEnergy) > perThousand * endEnergy ) + { + no_large_ediff ++; + if( (no_large_ediff% warnModulo) == 0 ) + { + no_warnings++; + G4cout << "WARNING - G4CoupledTransportation::AlongStepGetPIL() " + << " Energy change in Step is above 1^-3 relative value. " << G4endl + << " Relative change in 'tracking' step = " + << std::setw(15) << (endEnergy-startEnergy)/startEnergy << G4endl + << " Starting E= " << std::setw(12) << startEnergy / MeV << " MeV " << G4endl + << " Ending E= " << std::setw(12) << endEnergy / MeV << " MeV " << G4endl; + G4cout << " Energy has been corrected -- however, review" + << " field propagation parameters for accuracy." << G4endl; + if( (verboseLevel > 2 ) || (no_warnings<4) || (no_large_ediff == warnModulo * moduloFactor) ) + { + G4cout << " These include EpsilonStepMax(/Min) in G4FieldManager " + << " which determine fractional error per step for integrated quantities. " << G4endl + << " Note also the influence of the permitted number of integration steps." + << G4endl; + } + G4cerr << "ERROR - G4CoupledTransportation::AlongStepGetPIL()" << G4endl + << " Bad 'endpoint'. Energy change detected" + << " and corrected. " + << " Has occurred already " + << no_large_ediff << " times." << G4endl; + if( no_large_ediff == warnModulo * moduloFactor ) + { + warnModulo *= moduloFactor; + } + } + } +} + +#include "G4Transportation.hh" +G4bool G4CoupledTransportation::EnableUseMagneticMoment(G4bool useMoment) +{ + G4bool lastValue= fUseMagneticMoment; + fUseMagneticMoment= useMoment; + G4Transportation::fUseMagneticMoment= useMoment; + return lastValue; +} diff --git a/src/G4.10.04.p02fixes/G4IntersectingCone.cc b/src/G4.10.04.p02fixes/G4IntersectingCone.cc new file mode 100644 index 0000000..5acbc79 --- /dev/null +++ b/src/G4.10.04.p02fixes/G4IntersectingCone.cc @@ -0,0 +1,407 @@ +// +// ******************************************************************** +// * 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 source file +// +// +// G4IntersectingCone.cc +// +// Implementation of a utility class which calculates the intersection +// of an arbitrary line with a fixed cone +// -------------------------------------------------------------------- + +#include "G4IntersectingCone.hh" +#include "G4GeometryTolerance.hh" + +// +// Constructor +// +G4IntersectingCone::G4IntersectingCone( const G4double r[2], + const G4double z[2] ) +{ + const G4double halfCarTolerance + = 0.5 * G4GeometryTolerance::GetInstance()->GetSurfaceTolerance(); + + // What type of cone are we? + // + type1 = (std::abs(z[1]-z[0]) > std::abs(r[1]-r[0])); + + if (type1) // tube like + { + B = (r[1] - r[0]) / (z[1] - z[0]); + A = (r[0]*z[1] - r[1]*z[0]) / (z[1] -z[0]); + } + else // disk like + { + B = (z[1] - z[0]) / (r[1] - r[0]); + A = (z[0]*r[1] - z[1]*r[0]) / (r[1] - r[0]); + } + + // Calculate extent + // + rLo = std::min(r[0], r[1]) - halfCarTolerance; + rHi = std::max(r[0], r[1]) + halfCarTolerance; + zLo = std::min(z[0], z[1]) - halfCarTolerance; + zHi = std::max(z[0], z[1]) + halfCarTolerance; +} + + +// +// Fake default constructor - sets only member data and allocates memory +// for usage restricted to object persistency. +// +G4IntersectingCone::G4IntersectingCone( __void__& ) + : zLo(0.), zHi(0.), rLo(0.), rHi(0.), type1(false), A(0.), B(0.) +{ +} + + +// +// Destructor +// +G4IntersectingCone::~G4IntersectingCone() +{ +} + + +// +// HitOn +// +// Check r or z extent, as appropriate, to see if the point is possibly +// on the cone. +// +G4bool G4IntersectingCone::HitOn( const G4double r, + const G4double z ) +{ + // + // Be careful! The inequalities cannot be "<=" and ">=" here without + // punching a tiny hole in our shape! + // + if (type1) + { + if (z < zLo || z > zHi) return false; + } + else + { + if (r < rLo || r > rHi) return false; + } + + return true; +} + + +// +// LineHitsCone +// +// Calculate the intersection of a line with our conical surface, ignoring +// any phi division +// +G4int G4IntersectingCone::LineHitsCone( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + if (type1) + { + return LineHitsCone1( p, v, s1, s2 ); + } + else + { + return LineHitsCone2( p, v, s1, s2 ); + } +} + + +// +// LineHitsCone1 +// +// Calculate the intersections of a line with a conical surface. Only +// suitable if zPlane[0] != zPlane[1]. +// +// Equation of a line: +// +// x = x0 + s*tx y = y0 + s*ty z = z0 + s*tz +// +// Equation of a conical surface: +// +// x**2 + y**2 = (A + B*z)**2 +// +// Solution is quadratic: +// +// a*s**2 + b*s + c = 0 +// +// where: +// +// a = tx**2 + ty**2 - (B*tz)**2 +// +// b = 2*( px*vx + py*vy - B*(A + B*pz)*vz ) +// +// c = x0**2 + y0**2 - (A + B*z0)**2 +// +// Notice, that if a < 0, this indicates that the two solutions (assuming +// they exist) are in opposite cones (that is, given z0 = -A/B, one z < z0 +// and the other z > z0). For our shapes, the invalid solution is one +// which produces A + Bz < 0, or the one where Bz is smallest (most negative). +// Since Bz = B*s*tz, if B*tz > 0, we want the largest s, otherwise, +// the smaller. +// +// If there are two solutions on one side of the cone, we want to make +// sure that they are on the "correct" side, that is A + B*z0 + s*B*tz >= 0. +// +// If a = 0, we have a linear problem: s = c/b, which again gives one solution. +// This should be rare. +// +// For b*b - 4*a*c = 0, we also have one solution, which is almost always +// a line just grazing the surface of a the cone, which we want to ignore. +// However, there are two other, very rare, possibilities: +// a line intersecting the z axis and either: +// 1. At the same angle std::atan(B) to just miss one side of the cone, or +// 2. Intersecting the cone apex (0,0,-A/B) +// We *don't* want to miss these! How do we identify them? Well, since +// this case is rare, we can at least swallow a little more CPU than we would +// normally be comfortable with. Intersection with the z axis means +// x0*ty - y0*tx = 0. Case (1) means a==0, and we've already dealt with that +// above. Case (2) means a < 0. +// +// Now: x0*tx + y0*ty = 0 in terms of roundoff error. We can write: +// Delta = x0*tx + y0*ty +// b = 2*( Delta - B*(A + B*z0)*tz ) +// For: +// b*b - 4*a*c = epsilon +// where epsilon is small, then: +// Delta = epsilon/2/B +// +G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + static const G4double EPS = DBL_EPSILON; // Precision constant, + // originally it was 1E-6 + G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); + G4double tx = v.x(), ty = v.y(), tz = v.z(); + + // Value of radical can be inaccurate due to loss of precision + // if to calculate the coefficiets a,b,c like the following: + // G4double a = tx*tx + ty*ty - sqr(B*tz); + // G4double b = 2*( x0*tx + y0*ty - B*(A + B*z0)*tz); + // G4double c = x0*x0 + y0*y0 - sqr(A + B*z0); + // + // For more accurate calculation of radical the coefficients + // are splitted in two components, radial and along z-axis + // + G4double ar = tx*tx + ty*ty; + G4double az = sqr(B*tz); + G4double br = 2*(x0*tx + y0*ty); + G4double bz = 2*B*(A + B*z0)*tz; + G4double cr = x0*x0 + y0*y0; + G4double cz = sqr(A + B*z0); + + // Instead radical = b*b - 4*a*c + G4double arcz = 4*ar*cz; + G4double azcr = 4*az*cr; + G4double radical = (br*br - 4*ar*cr) + ((std::max(arcz,azcr) - 2*bz*br) + std::min(arcz,azcr)); + + // Find the coefficients + G4double a = ar - az; + G4double b = br - bz; + G4double c = cr - cz; + + if (radical < -EPS*std::fabs(b)) { return 0; } // No solution + + if (radical < EPS*std::fabs(b)) + { + // + // The radical is roughly zero: check for special, very rare, cases + // + if (std::fabs(a) > 1/kInfinity) + { + if(B==0.) { return 0; } + if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/B) ) + { + *s1 = -0.5*b/a; + return 1; + } + return 0; + } + } + else + { + radical = std::sqrt(radical); + } + + if (a > 1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + if (sa < sb) { *s1 = sa; *s2 = sb; } else { *s1 = sb; *s2 = sa; } + if (A + B*(z0+(*s1)*tz) < 0) { return 0; } + return 2; + } + else if (a < -1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + *s1 = (B*tz > 0)^(sa > sb) ? sb : sa; + return 1; + } + else if (std::fabs(b) < 1/kInfinity) + { + return 0; + } + else + { + *s1 = -c/b; + if (A + B*(z0+(*s1)*tz) < 0) { return 0; } + return 1; + } +} + + +// +// LineHitsCone2 +// +// See comments under LineHitsCone1. In this routine, case2, we have: +// +// Z = A + B*R +// +// The solution is still quadratic: +// +// a = tz**2 - B*B*(tx**2 + ty**2) +// +// b = 2*( (z0-A)*tz - B*B*(x0*tx+y0*ty) ) +// +// c = ( (z0-A)**2 - B*B*(x0**2 + y0**2) ) +// +// The rest is much the same, except some details. +// +// a > 0 now means we intersect only once in the correct hemisphere. +// +// a > 0 ? We only want solution which produces R > 0. +// since R = (z0+s*tz-A)/B, for tz/B > 0, this is the largest s +// for tz/B < 0, this is the smallest s +// thus, same as in case 1 ( since sign(tz/B) = sign(tz*B) ) +// +G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + static const G4double EPS = DBL_EPSILON; // Precision constant, + // originally it was 1E-6 + G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); + G4double tx = v.x(), ty = v.y(), tz = v.z(); + + // Special case which might not be so rare: B = 0 (precisely) + // + if (B==0) + { + if (std::fabs(tz) < 1/kInfinity) { return 0; } + + *s1 = (A-z0)/tz; + return 1; + } + + // Value of radical can be inaccurate due to loss of precision + // if to calculate the coefficiets a,b,c like the following: + // G4double a = tz*tz - B2*(tx*tx + ty*ty); + // G4double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) ); + // G4double c = sqr(z0-A) - B2*( x0*x0 + y0*y0 ); + // + // For more accurate calculation of radical the coefficients + // are splitted in two components, radial and along z-axis + // + G4double B2 = B*B; + + G4double az = tz*tz; + G4double ar = B2*(tx*tx + ty*ty); + G4double bz = 2*(z0-A)*tz; + G4double br = 2*B2*(x0*tx + y0*ty); + G4double cz = sqr(z0-A); + G4double cr = B2*(x0*x0 + y0*y0); + + // Instead radical = b*b - 4*a*c + G4double arcz = 4*ar*cz; + G4double azcr = 4*az*cr; + G4double radical = (br*br - 4*ar*cr) + ((std::max(arcz,azcr) - 2*bz*br) + std::min(arcz,azcr)); + + // Find the coefficients + G4double a = az - ar; + G4double b = bz - br; + G4double c = cz - cr; + + if (radical < -EPS*std::fabs(b)) { return 0; } // No solution + + if (radical < EPS*std::fabs(b)) + { + // + // The radical is roughly zero: check for special, very rare, cases + // + if (std::fabs(a) > 1/kInfinity) + { + if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/B) ) + { + *s1 = -0.5*b/a; + return 1; + } + return 0; + } + } + else + { + radical = std::sqrt(radical); + } + + if (a < -1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + if (sa < sb) { *s1 = sa; *s2 = sb; } else { *s1 = sb; *s2 = sa; } + if ((z0 + (*s1)*tz - A)/B < 0) { return 0; } + return 2; + } + else if (a > 1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + *s1 = (tz*B > 0)^(sa > sb) ? sb : sa; + return 1; + } + else if (std::fabs(b) < 1/kInfinity) + { + return 0; + } + else + { + *s1 = -c/b; + if ((z0 + (*s1)*tz - A)/B < 0) { return 0; } + return 1; + } +} diff --git a/src/G4.10.04.p02fixes/G4IntersectingCone.cc-mine b/src/G4.10.04.p02fixes/G4IntersectingCone.cc-mine new file mode 100644 index 0000000..683efac --- /dev/null +++ b/src/G4.10.04.p02fixes/G4IntersectingCone.cc-mine @@ -0,0 +1,382 @@ +// +// ******************************************************************** +// * 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: G4IntersectingCone.cc 95997 2016-03-07 13:16:25Z gcosmo $ +// +// +// -------------------------------------------------------------------- +// GEANT 4 class source file +// +// +// G4IntersectingCone.cc +// +// Implementation of a utility class which calculates the intersection +// of an arbitrary line with a fixed cone +// -------------------------------------------------------------------- + +#include "G4IntersectingCone.hh" +#include "G4GeometryTolerance.hh" + +// +// Constructor +// +G4IntersectingCone::G4IntersectingCone( const G4double r[2], + const G4double z[2] ) +{ + const G4double halfCarTolerance + = 0.5 * G4GeometryTolerance::GetInstance()->GetSurfaceTolerance(); + + // + // What type of cone are we? + // + type1 = (std::fabs(z[1]-z[0]) > std::fabs(r[1]-r[0])); + + if (type1) + { + B = (r[1]-r[0])/(z[1]-z[0]); // tube like + A = 0.5*( r[1]+r[0] - B*(z[1]+z[0]) ); + } + else + { + B = (z[1]-z[0])/(r[1]-r[0]); // disk like + A = 0.5*( z[1]+z[0] - B*(r[1]+r[0]) ); + } + // + // Calculate extent + // + if (r[0] < r[1]) + { + rLo = r[0]-halfCarTolerance; rHi = r[1]+halfCarTolerance; + } + else + { + rLo = r[1]-halfCarTolerance; rHi = r[0]+halfCarTolerance; + } + + if (z[0] < z[1]) + { + zLo = z[0]-halfCarTolerance; zHi = z[1]+halfCarTolerance; + } + else + { + zLo = z[1]-halfCarTolerance; zHi = z[0]+halfCarTolerance; + } +} + + +// +// Fake default constructor - sets only member data and allocates memory +// for usage restricted to object persistency. +// +G4IntersectingCone::G4IntersectingCone( __void__& ) + : zLo(0.), zHi(0.), rLo(0.), rHi(0.), type1(false), A(0.), B(0.) +{ +} + + +// +// Destructor +// +G4IntersectingCone::~G4IntersectingCone() +{ +} + + +// +// HitOn +// +// Check r or z extent, as appropriate, to see if the point is possibly +// on the cone. +// +G4bool G4IntersectingCone::HitOn( const G4double r, + const G4double z ) +{ + // + // Be careful! The inequalities cannot be "<=" and ">=" here without + // punching a tiny hole in our shape! + // + if (type1) + { + if (z < zLo || z > zHi) return false; + } + else + { + if (r < rLo || r > rHi) return false; + } + + return true; +} + + +// +// LineHitsCone +// +// Calculate the intersection of a line with our conical surface, ignoring +// any phi division +// +G4int G4IntersectingCone::LineHitsCone( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + if (type1) + { + return LineHitsCone1( p, v, s1, s2 ); + } + else + { + return LineHitsCone2( p, v, s1, s2 ); + } +} + + +// +// LineHitsCone1 +// +// Calculate the intersections of a line with a conical surface. Only +// suitable if zPlane[0] != zPlane[1]. +// +// Equation of a line: +// +// x = x0 + s*tx y = y0 + s*ty z = z0 + s*tz +// +// Equation of a conical surface: +// +// x**2 + y**2 = (A + B*z)**2 +// +// Solution is quadratic: +// +// a*s**2 + b*s + c = 0 +// +// where: +// +// a = x0**2 + y0**2 - (A + B*z0)**2 +// +// b = 2*( x0*tx + y0*ty - (A*B - B*B*z0)*tz) +// +// c = tx**2 + ty**2 - (B*tz)**2 +// +// Notice, that if a < 0, this indicates that the two solutions (assuming +// they exist) are in opposite cones (that is, given z0 = -A/B, one z < z0 +// and the other z > z0). For our shapes, the invalid solution is one +// which produces A + Bz < 0, or the one where Bz is smallest (most negative). +// Since Bz = B*s*tz, if B*tz > 0, we want the largest s, otherwise, +// the smaller. +// +// If there are two solutions on one side of the cone, we want to make +// sure that they are on the "correct" side, that is A + B*z0 + s*B*tz >= 0. +// +// If a = 0, we have a linear problem: s = c/b, which again gives one solution. +// This should be rare. +// +// For b*b - 4*a*c = 0, we also have one solution, which is almost always +// a line just grazing the surface of a the cone, which we want to ignore. +// However, there are two other, very rare, possibilities: +// a line intersecting the z axis and either: +// 1. At the same angle std::atan(B) to just miss one side of the cone, or +// 2. Intersecting the cone apex (0,0,-A/B) +// We *don't* want to miss these! How do we identify them? Well, since +// this case is rare, we can at least swallow a little more CPU than we would +// normally be comfortable with. Intersection with the z axis means +// x0*ty - y0*tx = 0. Case (1) means a==0, and we've already dealt with that +// above. Case (2) means a < 0. +// +// Now: x0*tx + y0*ty = 0 in terms of roundoff error. We can write: +// Delta = x0*tx + y0*ty +// b = 2*( Delta - (A*B + B*B*z0)*tz ) +// For: +// b*b - 4*a*c = epsilon +// where epsilon is small, then: +// Delta = epsilon/2/B +// +G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + static const G4double EPS = DBL_EPSILON; // Precision constant, + // originally it was 1E-6 + G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); + G4double tx = v.x(), ty = v.y(), tz = v.z(); + + G4double a = tx*tx + ty*ty - sqr(B*tz); + G4double b = 2*( x0*tx + y0*ty - (A*B + B*B*z0)*tz); + G4double c = x0*x0 + y0*y0 - sqr(A + B*z0); + + G4double radical = b*b - 4*a*c; + + if (radical < -EPS*EPS*b*b) { return 0; } // No solution + + if (radical < EPS*EPS*b*b) + { + // + // The radical is roughly zero: check for special, very rare, cases + // + if (std::fabs(a) > 1/kInfinity) + { + //if(B==0.) { return 0; } + //if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/(B+1e-99)) ) + { + *s1 = -0.5*b/a; + return 1; + } + return 0; + } + } + else + { + radical = std::sqrt(radical); + } + + if (a > 1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + if (sa < sb) { *s1 = sa; *s2 = sb; } else { *s1 = sb; *s2 = sa; } + if (A + B*(z0+(*s1)*tz) < 0) { return 0; } + return 2; + } + else if (a < -1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + *s1 = (B*tz > 0)^(sa > sb) ? sb : sa; + return 1; + } + else if (std::fabs(b) < 1/kInfinity) + { + return 0; + } + else + { + *s1 = -c/b; + if (A + B*(z0+(*s1)*tz) < 0) { return 0; } + return 1; + } +} + + +// +// LineHitsCone2 +// +// See comments under LineHitsCone1. In this routine, case2, we have: +// +// Z = A + B*R +// +// The solution is still quadratic: +// +// a = tz**2 - B*B*(tx**2 + ty**2) +// +// b = 2*( (z0-A)*tz - B*B*(x0*tx+y0*ty) ) +// +// c = ( (z0-A)**2 - B*B*(x0**2 + y0**2) ) +// +// The rest is much the same, except some details. +// +// a > 0 now means we intersect only once in the correct hemisphere. +// +// a > 0 ? We only want solution which produces R > 0. +// since R = (z0+s*tz-A)/B, for tz/B > 0, this is the largest s +// for tz/B < 0, this is the smallest s +// thus, same as in case 1 ( since sign(tz/B) = sign(tz*B) ) +// +G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, + const G4ThreeVector &v, + G4double *s1, G4double *s2 ) +{ + static const G4double EPS = DBL_EPSILON; // Precision constant, + // originally it was 1E-6 + G4double x0 = p.x(), y0 = p.y(), z0 = p.z(); + G4double tx = v.x(), ty = v.y(), tz = v.z(); + + // Special case which might not be so rare: B = 0 (precisely) + // + if (B==0) + { + if (std::fabs(tz) < 1/kInfinity) { return 0; } + + *s1 = (A-z0)/tz; + return 1; + } + + G4double B2 = B*B; + + G4double a = tz*tz - B2*(tx*tx + ty*ty); + G4double b = 2*( (z0-A)*tz - B2*(x0*tx + y0*ty) ); + G4double c = sqr(z0-A) - B2*( x0*x0 + y0*y0 ); + + G4double radical = b*b - 4*a*c; + + if (radical < -EPS*EPS*b*b) { return 0; } // No solution + + if (radical < EPS*EPS*b*b) + { + // + // The radical is roughly zero: check for special, very rare, cases + // + if (std::fabs(a) > 1/kInfinity) + { + //if ( std::fabs(x0*ty - y0*tx) < std::fabs(EPS/(B+1e-99)) ) + { + *s1 = -0.5*b/a; + return 1; + } + return 0; + } + } + else + { + radical = std::sqrt(radical); + } + + if (a < -1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + if (sa < sb) { *s1 = sa; *s2 = sb; } else { *s1 = sb; *s2 = sa; } + if ((z0 + (*s1)*tz - A)/B < 0) { return 0; } + return 2; + } + else if (a > 1/kInfinity) + { + G4double sa, sb, q = -0.5*( b + (b < 0 ? -radical : +radical) ); + sa = q/a; + sb = c/q; + *s1 = (tz*B > 0)^(sa > sb) ? sb : sa; + return 1; + } + else if (std::fabs(b) < 1/kInfinity) + { + return 0; + } + else + { + *s1 = -c/b; + if ((z0 + (*s1)*tz - A)/B < 0) { return 0; } + return 1; + } +} diff --git a/src/G4.10.04.p02fixes/G4OpenGLStoredSceneHandler.cc b/src/G4.10.04.p02fixes/G4OpenGLStoredSceneHandler.cc new file mode 100644 index 0000000..a4139c7 --- /dev/null +++ b/src/G4.10.04.p02fixes/G4OpenGLStoredSceneHandler.cc @@ -0,0 +1,638 @@ +// +// ******************************************************************** +// * 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: G4OpenGLStoredSceneHandler.cc 108544 2018-02-16 09:47:30Z gcosmo $ +// +// +// Andrew Walkden 10th February 1997 +// OpenGL stored scene - creates OpenGL display lists. + +#ifdef G4VIS_BUILD_OPENGL_DRIVER + +#include "G4OpenGLStoredSceneHandler.hh" + +#include "G4PhysicalVolumeModel.hh" +#include "G4LogicalVolumeModel.hh" +#include "G4VPhysicalVolume.hh" +#include "G4LogicalVolume.hh" +#include "G4Polyline.hh" +#include "G4Polymarker.hh" +#include "G4Text.hh" +#include "G4Circle.hh" +#include "G4Square.hh" +#include "G4Polyhedron.hh" +#include "G4AttHolder.hh" +#include "G4OpenGLTransform3D.hh" +#include "G4OpenGLViewer.hh" +#include "G4AttHolder.hh" + +#include + +G4int G4OpenGLStoredSceneHandler::fSceneIdCount = 0; + +G4int G4OpenGLStoredSceneHandler::fDisplayListId = 0; +G4bool G4OpenGLStoredSceneHandler::fMemoryForDisplayLists = true; +G4int G4OpenGLStoredSceneHandler::fDisplayListLimit = 50000; + +G4OpenGLStoredSceneHandler::PO::PO(): + fDisplayListId(0), + fPickName(0), + fpG4TextPlus(0), + fMarkerOrPolyline(false) +{} + +G4OpenGLStoredSceneHandler::PO::PO(const G4OpenGLStoredSceneHandler::PO& po): + fDisplayListId(po.fDisplayListId), + fTransform(po.fTransform), + fPickName(po.fPickName), + fColour(po.fColour), + fpG4TextPlus(po.fpG4TextPlus? new G4TextPlus(*po.fpG4TextPlus): 0), + fMarkerOrPolyline(po.fMarkerOrPolyline) +{} + +G4OpenGLStoredSceneHandler::PO::PO(G4int id, const G4Transform3D& tr): + fDisplayListId(id), + fTransform(tr), + fPickName(0), + fpG4TextPlus(0), + fMarkerOrPolyline(false) +{} + +G4OpenGLStoredSceneHandler::PO::~PO() +{ + delete fpG4TextPlus; +} + +G4OpenGLStoredSceneHandler::PO& G4OpenGLStoredSceneHandler::PO::operator= + (const G4OpenGLStoredSceneHandler::PO& rhs) +{ + if (&rhs == this) return *this; + fDisplayListId = rhs.fDisplayListId; + fTransform = rhs.fTransform; + fPickName = rhs.fPickName; + fColour = rhs.fColour; + fpG4TextPlus = rhs.fpG4TextPlus? new G4TextPlus(*rhs.fpG4TextPlus): 0; + fMarkerOrPolyline = rhs.fMarkerOrPolyline; + return *this; +} + +G4OpenGLStoredSceneHandler::TO::TO(): + fDisplayListId(0), + fPickName(0), + fStartTime(-DBL_MAX), + fEndTime(DBL_MAX), + fpG4TextPlus(0), + fMarkerOrPolyline(false) +{} + +G4OpenGLStoredSceneHandler::TO::TO(const G4OpenGLStoredSceneHandler::TO& to): + fDisplayListId(to.fDisplayListId), + fTransform(to.fTransform), + fPickName(to.fPickName), + fStartTime(to.fStartTime), + fEndTime(to.fEndTime), + fColour(to.fColour), + fpG4TextPlus(to.fpG4TextPlus? new G4TextPlus(*to.fpG4TextPlus): 0), + fMarkerOrPolyline(to.fMarkerOrPolyline) +{} + +G4OpenGLStoredSceneHandler::TO::TO(G4int id, const G4Transform3D& tr): + fDisplayListId(id), + fTransform(tr), + fPickName(0), + fStartTime(-DBL_MAX), + fEndTime(DBL_MAX), + fpG4TextPlus(0), + fMarkerOrPolyline(false) +{} + +G4OpenGLStoredSceneHandler::TO::~TO() +{ + delete fpG4TextPlus; +} + +G4OpenGLStoredSceneHandler::TO& G4OpenGLStoredSceneHandler::TO::operator= + (const G4OpenGLStoredSceneHandler::TO& rhs) +{ + if (&rhs == this) return *this; + fDisplayListId = rhs.fDisplayListId; + fTransform = rhs.fTransform; + fPickName = rhs.fPickName; + fStartTime = rhs.fStartTime; + fEndTime = rhs.fEndTime; + fColour = rhs.fColour; + fpG4TextPlus = rhs.fpG4TextPlus? new G4TextPlus(*rhs.fpG4TextPlus): 0; + fMarkerOrPolyline = rhs.fMarkerOrPolyline; + return *this; +} + +G4OpenGLStoredSceneHandler::G4OpenGLStoredSceneHandler +(G4VGraphicsSystem& system, + const G4String& name): +G4OpenGLSceneHandler (system, fSceneIdCount++, name), +fTopPODL (0) +{} + +G4OpenGLStoredSceneHandler::~G4OpenGLStoredSceneHandler () +{} + +void G4OpenGLStoredSceneHandler::BeginPrimitives +(const G4Transform3D& objectTransformation) +{ + G4OpenGLSceneHandler::BeginPrimitives (objectTransformation); + if (fReadyForTransients) glDrawBuffer (GL_FRONT); + // Display list setup moved to AddPrimitivePreamble. See notes there. +} + +void G4OpenGLStoredSceneHandler::EndPrimitives () +{ + // See all primitives immediately... At least soon... + ScaledFlush(); + glDrawBuffer (GL_BACK); + G4OpenGLSceneHandler::EndPrimitives (); +} + +void G4OpenGLStoredSceneHandler::BeginPrimitives2D +(const G4Transform3D& objectTransformation) +{ + G4OpenGLSceneHandler::BeginPrimitives2D(objectTransformation); + if (fReadyForTransients) glDrawBuffer (GL_FRONT); +} + +void G4OpenGLStoredSceneHandler::EndPrimitives2D () +{ + // See all primitives immediately... At least soon... + ScaledFlush(); + glDrawBuffer (GL_BACK); + G4OpenGLSceneHandler::EndPrimitives2D (); +} + +G4bool G4OpenGLStoredSceneHandler::AddPrimitivePreamble(const G4VMarker& visible) +{ + return AddPrimitivePreambleInternal(visible, true, false); +} +G4bool G4OpenGLStoredSceneHandler::AddPrimitivePreamble(const G4Polyline& visible) +{ + return AddPrimitivePreambleInternal(visible, false, true); +} +G4bool G4OpenGLStoredSceneHandler::AddPrimitivePreamble(const G4Polyhedron& visible) +{ + return AddPrimitivePreambleInternal(visible, false, false); +} + +G4bool G4OpenGLStoredSceneHandler::AddPrimitivePreambleInternal(const G4Visible& visible, bool isMarker, bool isPolyline) +{ +// Get applicable vis attributes for all primitives. + fpVisAttribs = fpViewer->GetApplicableVisAttributes(visible.GetVisAttributes()); + const G4Colour& c = GetColour (); + G4double opacity = c.GetAlpha (); + + G4bool transparency_enabled = true; + G4bool isMarkerNotHidden = true; + G4OpenGLViewer* pViewer = dynamic_cast(fpViewer); + if (pViewer) { + transparency_enabled = pViewer->transparency_enabled; + isMarkerNotHidden = pViewer->fVP.IsMarkerNotHidden(); + } + + G4bool isTransparent = opacity < 1.; + G4bool isMarkerOrPolyline = isMarker || isPolyline; + G4bool treatAsTransparent = transparency_enabled && isTransparent; + G4bool treatAsNotHidden = isMarkerNotHidden && isMarkerOrPolyline; + + if (fProcessing2D) glDisable (GL_DEPTH_TEST); + else { + if (isMarkerOrPolyline && isMarkerNotHidden) + glDisable (GL_DEPTH_TEST); + else {glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LEQUAL);} + } + + if (fThreePassCapable) { + + // Ensure transparent objects are drawn opaque ones and before + // non-hidden markers. The problem of blending/transparency/alpha + // is quite a tricky one - see History of opengl-V07-01-01/2/3. + if (!(fSecondPassForTransparency || fThirdPassForNonHiddenMarkers)) { + // First pass... + if (treatAsTransparent) { // Request pass for transparent objects... + fSecondPassForTransparencyRequested = true; + } + if (treatAsNotHidden) { // Request pass for non-hidden markers... + fThirdPassForNonHiddenMarkersRequested = true; + } + // On first pass, transparent objects and non-hidden markers are not drawn... + if (treatAsTransparent || treatAsNotHidden) { + return false; // No further processing. + } + } + + // On second pass, only transparent objects are drawn... + if (fSecondPassForTransparency) { + if (!treatAsTransparent) { + return false; // No further processing. + } + } + + // On third pass, only non-hidden markers are drawn... + if (fThirdPassForNonHiddenMarkers) { + if (!treatAsNotHidden) { + return false; // No further processing. + + } + } + } // fThreePassCapable + + // Loads G4Atts for picking... + G4bool isPicking = false; + if (fpViewer->GetViewParameters().IsPicking()) { + isPicking = true; + glLoadName(++fPickName); + G4AttHolder* holder = new G4AttHolder; + LoadAtts(visible, holder); + fPickMap[fPickName] = holder; + } + + // Can we re-use a display list? + const G4VSolid* pSolid = 0; + G4PhysicalVolumeModel* pPVModel = + dynamic_cast(fpModel); + if (fpViewer->GetViewParameters().GetVisAttributesModifiers().size()) + // Touchables have been modified - don't risk re-using display list. + goto end_of_display_list_reuse_test; + if (pPVModel) { + // Check that it isn't a G4LogicalVolumeModel (which is a sub-class of + // G4PhysicalVolumeModel). + G4LogicalVolumeModel* pLVModel = + dynamic_cast(pPVModel); + if (pLVModel) + // Logical volume model - don't re-use. + goto end_of_display_list_reuse_test; + if (pViewer->fVP.IsSection() || pViewer->fVP.IsCutaway()) + // sections and cutaways generate unique views of each model instance + goto end_of_display_list_reuse_test; + // If part of the geometry hierarchy, i.e., from a + // G4PhysicalVolumeModel, check if a display list already exists for + // this solid, re-use it if possible. We could be smarter, and + // recognise repeated branches of the geometry hierarchy, for + // example. But this algorithm should be secure, I think... + G4VPhysicalVolume* pPV = pPVModel->GetCurrentPV(); + if (!pPV) + // It's probably a dummy model, e.g., for a user-drawn hit? + goto end_of_display_list_reuse_test; + G4LogicalVolume* pLV = pPV->GetLogicalVolume(); + if (!pLV) + // Dummy model again? + goto end_of_display_list_reuse_test; + pSolid = pLV->GetSolid(); + EAxis axis = kRho; + G4VPhysicalVolume* pCurrentPV = pPVModel->GetCurrentPV(); + if (pCurrentPV -> IsReplicated ()) { + G4int nReplicas; + G4double width; + G4double offset; + G4bool consuming; + pCurrentPV->GetReplicationData(axis,nReplicas,width,offset,consuming); + } + // Provided it is not parametrised (because if so, the + // solid's parameters might have been changed)... + if (!(pCurrentPV -> IsParameterised ()) && + // Provided it is not replicated radially (because if so, the + // solid's parameters will have been changed)... + !(pCurrentPV -> IsReplicated () && axis == kRho) && + // ...and if the solid has already been rendered... + (fSolidMap.find (pSolid) != fSolidMap.end ())) { + fDisplayListId = fSolidMap [pSolid]; + PO po(fDisplayListId,fObjectTransformation); + if (isPicking) po.fPickName = fPickName; + po.fColour = c; + po.fMarkerOrPolyline = isMarkerOrPolyline; + fPOList.push_back(po); + // No need to test if gl commands are used (result of + // ExtraPOProcessing) because we have already decided they will + // not, at least not here. Also, pass a dummy G4Visible since + // not relevant for G4PhysicalVolumeModel. + (void) ExtraPOProcessing(G4Visible(), fPOList.size() - 1); + return false; // No further processing. + } + } +end_of_display_list_reuse_test: + + // Because of our need to control colour of transients (display by + // time fading), display lists may only cover a single primitive. + // So display list setup is here. + + if (fMemoryForDisplayLists) { + fDisplayListId = glGenLists (1); + if (glGetError() == GL_OUT_OF_MEMORY || + fDisplayListId > fDisplayListLimit) { + G4cout << + "********************* WARNING! ********************" + "\n* Display list limit reached in OpenGL." + "\n* Continuing drawing WITHOUT STORING. Scene only partially refreshable." + "\n* Current limit: " << fDisplayListLimit << + ". Change with \"/vis/ogl/set/displayListLimit\"." + "\n***************************************************" + << G4endl; + fMemoryForDisplayLists = false; + } + } + + if (pSolid) fSolidMap [pSolid] = fDisplayListId; + + if (fMemoryForDisplayLists) { + if (fReadyForTransients) { + TO to(fDisplayListId, fObjectTransformation); + if (isPicking) to.fPickName = fPickName; + to.fColour = c; + to.fStartTime = fpVisAttribs->GetStartTime(); + to.fEndTime = fpVisAttribs->GetEndTime(); + to.fMarkerOrPolyline = isMarkerOrPolyline; + fTOList.push_back(to); + // For transient objects, colour, transformation, are kept in + // the TO, so should *not* be in the display list. As mentioned + // above, in some cases (display-by-time fading) we need to have + // independent control of colour. But for now transform and set + // colour for immediate display. + glPushMatrix(); + G4OpenGLTransform3D oglt (fObjectTransformation); + glMultMatrixd (oglt.GetGLMatrix ()); + if (transparency_enabled) { + glColor4d(c.GetRed(),c.GetGreen(),c.GetBlue(),c.GetAlpha()); + } else { + glColor3d(c.GetRed(),c.GetGreen(),c.GetBlue()); + } + (void) ExtraTOProcessing(visible, fTOList.size() - 1); + // Ignore return value of the above. If this visible does not use + // gl commands, a display list is created that is empty and not + // used. + glNewList (fDisplayListId, GL_COMPILE_AND_EXECUTE); + } else { + PO po(fDisplayListId, fObjectTransformation); + if (isPicking) po.fPickName = fPickName; + po.fColour = c; + po.fMarkerOrPolyline = isMarkerOrPolyline; + fPOList.push_back(po); + // For permanent objects, colour is kept in the PO, so should + // *not* be in the display list. This is so that sub-classes + // may implement colour modifications according to their own + // criteria, e.g., scen tree slider in Qt. But for now set + // colour for immediate display. + if (transparency_enabled) { + glColor4d(c.GetRed(),c.GetGreen(),c.GetBlue(),c.GetAlpha()); + } else { + glColor3d(c.GetRed(),c.GetGreen(),c.GetBlue()); + } + G4bool usesGLCommands = ExtraPOProcessing(visible, fPOList.size() - 1); + // Transients are displayed as they come (GL_COMPILE_AND_EXECUTE + // above) but persistents are compiled into display lists + // (GL_COMPILE only) and then drawn from the display lists with + // their fObjectTransformation as stored in fPOList. Thus, + // there is no need to do glMultMatrixd here. If + // ExtraPOProcessing says the visible object does not use gl + // commands, simply return and abandon further processing. It + // is assumed that all relevant information is kept in the + // POList. + if (!usesGLCommands) return false; + glNewList (fDisplayListId, GL_COMPILE); + } + } else { // Out of memory (or being used when display lists not required). + glPushMatrix(); + G4OpenGLTransform3D oglt (fObjectTransformation); + glMultMatrixd (oglt.GetGLMatrix ()); + if (transparency_enabled) { + glColor4d(c.GetRed(),c.GetGreen(),c.GetBlue(),c.GetAlpha()); + } else { + glColor3d(c.GetRed(),c.GetGreen(),c.GetBlue()); + } + } + + if (fProcessing2D) { + // Push current 3D world matrices and load identity to define screen + // coordinates... + glMatrixMode (GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + if (pViewer) { + pViewer->g4GlOrtho (-1., 1., -1., 1., -G4OPENGL_FLT_BIG, G4OPENGL_FLT_BIG); + } + glMatrixMode (GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + G4OpenGLTransform3D oglt (fObjectTransformation); + glMultMatrixd (oglt.GetGLMatrix ()); + glDisable (GL_LIGHTING); + } else { + glEnable (GL_LIGHTING); + } + + return true; +} + +void G4OpenGLStoredSceneHandler::AddPrimitivePostamble() +{ + if (fProcessing2D) { + // Pop current 3D world matrices back again... + glMatrixMode (GL_PROJECTION); + glPopMatrix(); + glMatrixMode (GL_MODELVIEW); + glPopMatrix(); + } + + // if ((glGetError() == GL_TABLE_TOO_LARGE) || (glGetError() == GL_OUT_OF_MEMORY)) { // Could close? + if (glGetError() == GL_OUT_OF_MEMORY) { // Could close? + G4cerr << + "ERROR: G4OpenGLStoredSceneHandler::AddPrimitivePostamble: Failure" + " to allocate display List for fTopPODL - try OpenGL Immediated mode." + << G4endl; + } + if (fMemoryForDisplayLists) { + glEndList(); + if (glGetError() == GL_OUT_OF_MEMORY) { // Could close? + G4cerr << + "ERROR: G4OpenGLStoredSceneHandler::AddPrimitivePostamble: Failure" + " to allocate display List for fTopPODL - try OpenGL Immediated mode." + << G4endl; + } + } + if (fReadyForTransients || !fMemoryForDisplayLists) { + glPopMatrix(); + } +} + +void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Polyline& polyline) +{ + G4bool furtherprocessing = AddPrimitivePreamble(polyline); + if (furtherprocessing) { + G4OpenGLSceneHandler::AddPrimitive(polyline); + AddPrimitivePostamble(); + } +} + +void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Polymarker& polymarker) +{ + G4bool furtherprocessing = AddPrimitivePreamble(polymarker); + if (furtherprocessing) { + G4OpenGLSceneHandler::AddPrimitive(polymarker); + AddPrimitivePostamble(); + } +} + +void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Text& text) +{ + // Note: colour is still handled in + // G4OpenGLSceneHandler::AddPrimitive(const G4Text&), so it still + // gets into the display list + G4bool furtherprocessing = AddPrimitivePreamble(text); + if (furtherprocessing) { + G4OpenGLSceneHandler::AddPrimitive(text); + AddPrimitivePostamble(); + } +} + +void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Circle& circle) +{ + G4bool furtherprocessing = AddPrimitivePreamble(circle); + if (furtherprocessing) { + G4OpenGLSceneHandler::AddPrimitive(circle); + AddPrimitivePostamble(); + } +} + +void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Square& square) +{ + G4bool furtherprocessing = AddPrimitivePreamble(square); + if (furtherprocessing) { + G4OpenGLSceneHandler::AddPrimitive(square); + AddPrimitivePostamble(); + } +} + +void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Scale& scale) +{ + // Let base class split into primitives. + G4OpenGLSceneHandler::AddPrimitive(scale); +} + +void G4OpenGLStoredSceneHandler::AddPrimitive (const G4Polyhedron& polyhedron) +{ + // Note: colour is still handled in + // G4OpenGLSceneHandler::AddPrimitive(const G4Polyhedron&), so it still + // gets into the display list + G4bool furtherprocessing = AddPrimitivePreamble(polyhedron); + if (furtherprocessing) { + G4OpenGLSceneHandler::AddPrimitive(polyhedron); + AddPrimitivePostamble(); + } +} + +void G4OpenGLStoredSceneHandler::BeginModeling () { + G4VSceneHandler::BeginModeling(); + /* Debug... + fDisplayListId = glGenLists (1); + G4cout << "OGL::fDisplayListId (start): " << fDisplayListId << G4endl; + */ +} + +void G4OpenGLStoredSceneHandler::EndModeling () { + // Make a List which calls the other lists. + fTopPODL = glGenLists (1); + if (glGetError() == GL_OUT_OF_MEMORY) { // Could pre-allocate? + G4cerr << + "ERROR: G4OpenGLStoredSceneHandler::EndModeling: Failure to allocate" + " display List for fTopPODL - try OpenGL Immediated mode." + << G4endl; + } else { + + glNewList (fTopPODL, GL_COMPILE); { + for (size_t i = 0; i < fPOList.size (); i++) { + glPushMatrix(); + G4OpenGLTransform3D oglt (fPOList[i].fTransform); + glMultMatrixd (oglt.GetGLMatrix ()); + if (fpViewer->GetViewParameters().IsPicking()) + glLoadName(fPOList[i].fPickName); + glCallList (fPOList[i].fDisplayListId); + glPopMatrix(); + } + } + glEndList (); + + if (glGetError() == GL_OUT_OF_MEMORY) { // Could close? + G4cerr << + "ERROR: G4OpenGLStoredSceneHandler::EndModeling: Failure to allocate" + " display List for fTopPODL - try OpenGL Immediated mode." + << G4endl; + } + } + + G4VSceneHandler::EndModeling (); +} + +void G4OpenGLStoredSceneHandler::ClearStore () { + + //G4cout << "G4OpenGLStoredSceneHandler::ClearStore" << G4endl; + + G4VSceneHandler::ClearStore (); // Sets need kernel visit, etc. + + // Delete OpenGL permanent display lists. + for (size_t i = 0; i < fPOList.size (); i++) + glDeleteLists (fPOList[i].fDisplayListId, 1); + if (fTopPODL) glDeleteLists (fTopPODL, 1); + fTopPODL = 0; + + // Clear other lists, dictionary, etc. + fPOList.clear (); + fSolidMap.clear (); + ClearAndDestroyAtts(); + + // ...and clear transient store... + for (size_t i = 0; i < fTOList.size (); i++) + glDeleteLists(fTOList[i].fDisplayListId, 1); + fTOList.clear (); + + fMemoryForDisplayLists = true; +} + +void G4OpenGLStoredSceneHandler::ClearTransientStore () +{ + //G4cout << "G4OpenGLStoredSceneHandler::ClearTransientStore" << G4endl; + + // Delete OpenGL transient display lists and Transient Objects themselves. + for (size_t i = 0; i < fTOList.size (); i++) + glDeleteLists(fTOList[i].fDisplayListId, 1); + fTOList.clear (); + + fMemoryForDisplayLists = true; + + // Redraw the scene ready for the next event. + if (fpViewer) { + fpViewer -> SetView (); + fpViewer -> ClearView (); + fpViewer -> DrawView (); + } +} + + +#endif diff --git a/src/G4.10.04.p02fixes/G4OpenGLViewer.cc b/src/G4.10.04.p02fixes/G4OpenGLViewer.cc new file mode 100644 index 0000000..ef2a93d --- /dev/null +++ b/src/G4.10.04.p02fixes/G4OpenGLViewer.cc @@ -0,0 +1,1643 @@ +// +// ******************************************************************** +// * 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: G4OpenGLViewer.cc 107329 2017-11-08 16:41:26Z gcosmo $ +// +// +// Andrew Walkden 27th March 1996 +// OpenGL view - opens window, hard copy, etc. + +#ifdef G4VIS_BUILD_OPENGL_DRIVER + +#include "G4ios.hh" +#include "G4SystemOfUnits.hh" +#include "G4OpenGLViewer.hh" +#include "G4OpenGLSceneHandler.hh" +#include "G4OpenGLTransform3D.hh" +#include "G4OpenGL2PSAction.hh" + +#include "G4TransportationManager.hh" +#include "G4Navigator.hh" +#include "G4Material.hh" +#include "G4FieldManager.hh" +#include "G4Field.hh" + +#include "G4Scene.hh" +#include "G4VisExtent.hh" +#include "G4LogicalVolume.hh" +#include "G4VSolid.hh" +#include "G4Point3D.hh" +#include "G4Normal3D.hh" +#include "G4Plane3D.hh" +#include "G4AttHolder.hh" +#include "G4AttCheck.hh" +#include "G4Text.hh" + +#ifdef G4OPENGL_VERSION_2 +// We need to have a Wt gl drawer because we will draw inside the WtGL component (ImmediateWtViewer) +#include "G4OpenGLVboDrawer.hh" +#endif + +// GL2PS +#include "Geant4_gl2ps.h" + +#include +#include +#include + +#include + +G4OpenGLViewer::G4OpenGLViewer (G4OpenGLSceneHandler& scene): +G4VViewer (scene, -1), +#ifdef G4OPENGL_VERSION_2 +fVboDrawer(NULL), +#endif +fPrintColour (true), +fVectoredPs (true), +fOpenGLSceneHandler(scene), +background (G4Colour(0.,0.,0.)), +transparency_enabled (true), +antialiasing_enabled (false), +haloing_enabled (false), +fStartTime(-DBL_MAX), +fEndTime(DBL_MAX), +fFadeFactor(0.), +fDisplayHeadTime(false), +fDisplayHeadTimeX(-0.9), +fDisplayHeadTimeY(-0.9), +fDisplayHeadTimeSize(24.), +fDisplayHeadTimeRed(0.), +fDisplayHeadTimeGreen(1.), +fDisplayHeadTimeBlue(1.), +fDisplayLightFront(false), +fDisplayLightFrontX(0.), +fDisplayLightFrontY(0.), +fDisplayLightFrontZ(0.), +fDisplayLightFrontT(0.), +fDisplayLightFrontRed(0.), +fDisplayLightFrontGreen(1.), +fDisplayLightFrontBlue(0.), +fRot_sens(1.), +fPan_sens(0.01), +fWinSize_x(0), +fWinSize_y(0), +fDefaultExportImageFormat("pdf"), +fExportImageFormat("pdf"), +fExportFilenameIndex(0), +fPrintSizeX(-1), +fPrintSizeY(-1), +fPointSize (0), +fDefaultExportFilename("G4OpenGL"), +fSizeHasChanged(0), +fGl2psDefaultLineWith(1), +fGl2psDefaultPointSize(2), +fGlViewInitialized(false), +fIsGettingPickInfos(false) +#ifdef G4OPENGL_VERSION_2 +,fShaderProgram(0) +,fVertexPositionAttribute(0) +,fVertexNormalAttribute(0) +,fpMatrixUniform(0) +,fcMatrixUniform(0) +,fmvMatrixUniform(0) +,fnMatrixUniform(0) +#endif +{ + // Make changes to view parameters for OpenGL... + fVP.SetAutoRefresh(true); + fDefaultVP.SetAutoRefresh(true); + + fGL2PSAction = new G4OpenGL2PSAction(); + + // add supported export image format + addExportImageFormat("eps"); + addExportImageFormat("ps"); + addExportImageFormat("pdf"); + addExportImageFormat("svg"); + + // Change the default name + fExportFilename += fDefaultExportFilename + "_" + GetShortName().data(); + + // glClearColor (0.0, 0.0, 0.0, 0.0); + // glClearDepth (1.0); + // glDisable (GL_BLEND); + // glDisable (GL_LINE_SMOOTH); + // glDisable (GL_POLYGON_SMOOTH); + +} + +G4OpenGLViewer::~G4OpenGLViewer () +{ + delete fGL2PSAction; +} + +void G4OpenGLViewer::InitializeGLView () +{ +#ifdef G4OPENGL_VERSION_2 + if (fVboDrawer) { + + // First, load a simple shader + fShaderProgram = glCreateProgram(); + Shader vertexShader = glCreateShader(GL_VERTEX_SHADER); + const char * vSrc = fVboDrawer->getVertexShaderSrc(); + glShaderSource(vertexShader, 1, &vSrc, NULL); + glCompileShader(vertexShader); + glAttachShader(fShaderProgram, vertexShader); + + Shader fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + const char * fSrc = fVboDrawer->getFragmentShaderSrc(); + glShaderSource(fragmentShader, 1, &fSrc, NULL); + glCompileShader(fragmentShader); + + glAttachShader(fShaderProgram, fragmentShader); + glLinkProgram(fShaderProgram); + glUseProgram(fShaderProgram); + + // UniformLocation uColor = getUniformLocation(fShaderProgram, "uColor"); + // uniform4fv(uColor, [0.0, 0.3, 0.0, 1.0]); + + // Extract the references to the attributes from the shader. + + fVertexPositionAttribute = + glGetAttribLocation(fShaderProgram, "aVertexPosition"); + + + glEnableVertexAttribArray(fVertexPositionAttribute); + + // Extract the references the uniforms from the shader + fpMatrixUniform = glGetUniformLocation(fShaderProgram, "uPMatrix"); + fcMatrixUniform = glGetUniformLocation(fShaderProgram, "uCMatrix"); + fmvMatrixUniform = glGetUniformLocation(fShaderProgram, "uMVMatrix"); + fnMatrixUniform = glGetUniformLocation(fShaderProgram, "uNMatrix"); + ftMatrixUniform = glGetUniformLocation(fShaderProgram, "uTMatrix"); + + /* glUniformMatrix4fv(fcMatrixUniform, 1, 0, identity); + glUniformMatrix4fv(fpMatrixUniform, 1, 0, identity); + glUniformMatrix4fv(ftMatrixUniform, 1, 0, identity); + glUniformMatrix4fv(fmvMatrixUniform, 1, 0, identity); + */ + // We have to set that in order to avoid calls on opengl commands before all is ready + fGlViewInitialized = true; + } +#endif + + if (fWinSize_x == 0) { + fWinSize_x = fVP.GetWindowSizeHintX(); + } + if (fWinSize_y == 0) { + fWinSize_y = fVP.GetWindowSizeHintY(); + } + + glClearColor (0.0, 0.0, 0.0, 0.0); + glClearDepth (1.0); +#ifndef G4OPENGL_VERSION_2 + glDisable (GL_LINE_SMOOTH); + glDisable (GL_POLYGON_SMOOTH); +#endif + +// clear the buffers and window? + ClearView (); + FinishView (); + + glDepthFunc (GL_LEQUAL); + glDepthMask (GL_TRUE); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +} + +void G4OpenGLViewer::ClearView () { + ClearViewWithoutFlush(); + + if(!isFramebufferReady()) { + return; + } + + glFlush(); +} + + +void G4OpenGLViewer::ClearViewWithoutFlush () { + // Ready for clear ? + // See : http://lists.apple.com/archives/mac-opengl/2012/Jul/msg00038.html + if(!isFramebufferReady()) { + return; + } + + glClearColor (background.GetRed(), + background.GetGreen(), + background.GetBlue(), + 1.); + glClearDepth (1.0); + //Below line does not compile with Mesa includes. + //glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear (GL_COLOR_BUFFER_BIT); + glClear (GL_DEPTH_BUFFER_BIT); + glClear (GL_STENCIL_BUFFER_BIT); +} + + +void G4OpenGLViewer::ResizeWindow(unsigned int aWidth, unsigned int aHeight) { + if ((fWinSize_x != aWidth) || (fWinSize_y != aHeight)) { + fWinSize_x = aWidth; + fWinSize_y = aHeight; + fSizeHasChanged = true; + } else { + fSizeHasChanged = false; + } +} + +/** + * Set the viewport of the scene + * MAXIMUM SIZE is : + * GLint dims[2]; + * glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); + */ +void G4OpenGLViewer::ResizeGLView() +{ + // Check size + GLint dims[2]; + dims[0] = 0; + dims[1] = 0; + + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); + + if ((dims[0] !=0 ) && (dims[1] !=0)) { + + if (fWinSize_x > (unsigned)dims[0]) { + G4cerr << "Try to resize view greater than max X viewport dimension. Desired size "< (unsigned)dims[1]) { + G4cerr << "Try to resize view greater than max Y viewport dimension. Desired size "< fWinSize_x) { + ratioX = ((G4double)fWinSize_y) / ((G4double)fWinSize_x); + } + if (fWinSize_x > fWinSize_y) { + ratioY = ((G4double)fWinSize_x) / ((G4double)fWinSize_y); + } + + // Get radius of scene, etc. + // Note that this procedure properly takes into account zoom, dolly and pan. + const G4Point3D targetPoint + = fSceneHandler.GetScene()->GetStandardTargetPoint() + + fVP.GetCurrentTargetPoint (); + G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius(); + if(radius<=0.) radius = 1.; + const G4double cameraDistance = fVP.GetCameraDistance (radius); + const G4Point3D cameraPosition = + targetPoint + cameraDistance * fVP.GetViewpointDirection().unit(); + const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius); + const GLdouble pfar = fVP.GetFarDistance (cameraDistance, pnear, radius); + const GLdouble right = fVP.GetFrontHalfHeight (pnear, radius) * ratioY; + const GLdouble left = -right; + const GLdouble top = fVP.GetFrontHalfHeight (pnear, radius) * ratioX; + const GLdouble bottom = -top; + + // FIXME + ResizeGLView(); + //SHOULD SetWindowsSizeHint()... + + glMatrixMode (GL_PROJECTION); // set up Frustum. + glLoadIdentity(); + + const G4Vector3D scaleFactor = fVP.GetScaleFactor(); + glScaled(scaleFactor.x(),scaleFactor.y(),scaleFactor.z()); + + if (fVP.GetFieldHalfAngle() == 0.) { + g4GlOrtho (left, right, bottom, top, pnear, pfar); + } + else { + g4GlFrustum (left, right, bottom, top, pnear, pfar); + } + + glMatrixMode (GL_MODELVIEW); // apply further transformations to scene. + glLoadIdentity(); + + const G4Normal3D& upVector = fVP.GetUpVector (); + G4Point3D gltarget; + if (cameraDistance > 1.e-6 * radius) { + gltarget = targetPoint; + } + else { + gltarget = targetPoint - radius * fVP.GetViewpointDirection().unit(); + } + + const G4Point3D& pCamera = cameraPosition; // An alias for brevity. + + g4GluLookAt (pCamera.x(), pCamera.y(), pCamera.z(), // Viewpoint. + gltarget.x(), gltarget.y(), gltarget.z(), // Target point. + upVector.x(), upVector.y(), upVector.z()); // Up vector. + // Light position is "true" light direction, so must come after gluLookAt. + glLightfv (GL_LIGHT0, GL_POSITION, lightPosition); + + // The idea is to use back-to-back clipping planes. This can cut an object + // down to just a few pixels, which can make it difficult to see. So, for + // now, comment this out and use the generic (Boolean) method, via + // G4VSolid* G4OpenGLSceneHandler::CreateSectionSolid () + // { return G4VSceneHandler::CreateSectionSolid(); } +// if (fVP.IsSection () ) { // pair of back to back clip planes. +// const G4Plane3D& sp = fVP.GetSectionPlane (); +// double sArray[4]; +// sArray[0] = sp.a(); +// sArray[1] = sp.b(); +// sArray[2] = sp.c(); +// sArray[3] = sp.d() + radius * 1.e-05; +// glClipPlane (GL_CLIP_PLANE0, sArray); +// glEnable (GL_CLIP_PLANE0); +// sArray[0] = -sp.a(); +// sArray[1] = -sp.b(); +// sArray[2] = -sp.c(); +// sArray[3] = -sp.d() + radius * 1.e-05; +// glClipPlane (GL_CLIP_PLANE1, sArray); +// glEnable (GL_CLIP_PLANE1); +// } else { +// glDisable (GL_CLIP_PLANE0); +// glDisable (GL_CLIP_PLANE1); +// } + + // What we call intersection of cutaways is easy in OpenGL. You + // just keep cutting. Unions are more tricky - you have to have + // multiple passes and this is handled in + // G4OpenGLImmediate/StoredViewer::ProcessView. + const G4Planes& cutaways = fVP.GetCutawayPlanes(); + size_t nPlanes = cutaways.size(); + if (fVP.IsCutaway() && + fVP.GetCutawayMode() == G4ViewParameters::cutawayIntersection && + nPlanes > 0) { + double a[4]; + a[0] = cutaways[0].a(); + a[1] = cutaways[0].b(); + a[2] = cutaways[0].c(); + a[3] = cutaways[0].d(); + glClipPlane (GL_CLIP_PLANE2, a); + glEnable (GL_CLIP_PLANE2); + if (nPlanes > 1) { + a[0] = cutaways[1].a(); + a[1] = cutaways[1].b(); + a[2] = cutaways[1].c(); + a[3] = cutaways[1].d(); + glClipPlane (GL_CLIP_PLANE3, a); + glEnable (GL_CLIP_PLANE3); + } + if (nPlanes > 2) { + a[0] = cutaways[2].a(); + a[1] = cutaways[2].b(); + a[2] = cutaways[2].c(); + a[3] = cutaways[2].d(); + glClipPlane (GL_CLIP_PLANE4, a); + glEnable (GL_CLIP_PLANE4); + } + } else { + glDisable (GL_CLIP_PLANE2); + glDisable (GL_CLIP_PLANE3); + glDisable (GL_CLIP_PLANE4); + } + + // Background. + background = fVP.GetBackgroundColour (); + +} + + + +void G4OpenGLViewer::ResetView () { + G4VViewer::ResetView(); + fRot_sens = 1; + fPan_sens = 0.01; +} + + +void G4OpenGLViewer::HaloingFirstPass () { + + //To perform haloing, first Draw all information to the depth buffer + //alone, using a chunky line width, and then Draw all info again, to + //the colour buffer, setting a thinner line width an the depth testing + //function to less than or equal, so if two lines cross, the one + //passing behind the other will not pass the depth test, and so not + //get rendered either side of the infront line for a short distance. + + //First, disable writing to the colo(u)r buffer... + glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + //Now enable writing to the depth buffer... + glDepthMask (GL_TRUE); + glDepthFunc (GL_LESS); + glClearDepth (1.0); + + //Finally, set the line width to something wide... + ChangeLineWidth(3.0); + +} + +void G4OpenGLViewer::HaloingSecondPass () { + + //And finally, turn the colour buffer back on with a sesible line width... + glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDepthFunc (GL_LEQUAL); + ChangeLineWidth(1.0); + +} + +G4String G4OpenGLViewer::Pick(GLdouble x, GLdouble y) +{ + const std::vector < G4OpenGLViewerPickMap* > & pickMap = GetPickDetails(x,y); + G4String txt = ""; + if (pickMap.size() == 0) { +// txt += "No hits recorded.";; + } else { +#ifdef LAYERED_GEOMETRY_PICKING_EXTENSIONS + G4ThreeVector xlast; + for (unsigned int a = 0; a < pickMap.size(); a++) { + G4ThreeVector x = pickMap[a]->getPickCoordinates3D(); + if (!x.isNear(xlast, 0.001 * cm)) { + txt += pickMap[a]->print(); + xlast = x; + } + } +#else + for (unsigned int a=0; a < pickMap.size(); a++) { + if (pickMap[a]->getAttributes().size() > 0) { + txt += pickMap[a]->print(); + } + } +#endif + } + return txt; +} + +const std::vector < G4OpenGLViewerPickMap* > & G4OpenGLViewer::GetPickDetails(GLdouble x, GLdouble y) +{ + static std::vector < G4OpenGLViewerPickMap* > pickMapVector; + for (auto pickMap: pickMapVector) { + delete pickMap; + } + pickMapVector.clear(); + + const G4int BUFSIZE = 512; + GLuint selectBuffer[BUFSIZE]; + glSelectBuffer(BUFSIZE, selectBuffer); + glRenderMode(GL_SELECT); + glInitNames(); + glPushName(0); + glMatrixMode(GL_PROJECTION); + G4double currentProjectionMatrix[16]; + glGetDoublev(GL_PROJECTION_MATRIX, currentProjectionMatrix); + glPushMatrix(); + glLoadIdentity(); + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); +/* G4cout + << "viewport, x,y: " + << viewport[0] << ',' << viewport[1] << ',' << viewport[2] << ',' << viewport[3] + << ", " << x << ',' << y + << G4endl; +*/ + fIsGettingPickInfos = true; + // Define 5x5 pixel pick area + g4GluPickMatrix(x, viewport[3] - y, 5., 5., viewport); + glMultMatrixd(currentProjectionMatrix); + glMatrixMode(GL_MODELVIEW); + DrawView(); + GLint hits = glRenderMode(GL_RENDER); + fIsGettingPickInfos = false; + if (hits < 0) { + G4cout << "Too many hits. Zoom in to reduce overlaps." << G4endl; + goto restoreMatrices; + } + if (hits > 0) { + GLuint* p = selectBuffer; + for (GLint i = 0; i < hits; ++i) { + GLuint nnames = *p++; +#ifdef LAYERED_GEOMETRY_PICKING_EXTENSIONS + G4OpenGLViewerPickMap* pickMap = new G4OpenGLViewerPickMap(); + double zmin = *p++; + double zmax = *p++; + zmin /= (1LL << 32) - 1.0; + zmax /= (1LL << 32) - 1.0; + double model[16]; + double proj[16]; + GLint view[4]; + double gx[4]; + glGetDoublev(GL_MODELVIEW_MATRIX,model); + glGetDoublev(GL_PROJECTION_MATRIX,proj); + glGetIntegerv(GL_VIEWPORT,view); + gluUnProject(x,y,(zmin+zmax)/2,model,proj,view,&gx[0],&gx[1],&gx[2]); + pickMap->setPickCoordinates3D(G4ThreeVector(gx[0],gx[1],gx[2])); +#else + // This bit of debug code or... + //GLuint zmin = *p++; + //GLuint zmax = *p++; + //G4cout << "Hit " << i << ": " << nnames << " names" + // << "\nzmin: " << zmin << ", zmax: " << zmax << G4endl; + // ...just increment the pointer + p++; + p++; +#endif + for (GLuint j = 0; j < nnames; ++j) { + GLuint name = *p++; + std::map::iterator iter = + fOpenGLSceneHandler.fPickMap.find(name); + if (iter != fOpenGLSceneHandler.fPickMap.end()) { + G4AttHolder* attHolder = iter->second; + if(attHolder && attHolder->GetAttDefs().size()) { + for (size_t iAtt = 0; + iAtt < attHolder->GetAttDefs().size(); ++iAtt) { + std::ostringstream oss; + oss << G4AttCheck(attHolder->GetAttValues()[iAtt], + attHolder->GetAttDefs()[iAtt]); + G4OpenGLViewerPickMap* pickMap = new G4OpenGLViewerPickMap(); +// G4cout +// << "i,j, attHolder->GetAttDefs().size(): " +// << i << ',' << j +// << ", " << attHolder->GetAttDefs().size() +// << G4endl; +// G4cout << "G4OpenGLViewer::GetPickDetails: " << oss.str() << G4endl; + pickMap->addAttributes(oss.str()); + pickMap->setHitNumber(i); + pickMap->setSubHitNumber(j); + pickMap->setPickName(name); + pickMapVector.push_back(pickMap); + } + } + } + } + } + } + +restoreMatrices: + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + return pickMapVector; +} + +GLubyte* G4OpenGLViewer::grabPixels +(int inColor, unsigned int width, unsigned int height) { + + GLubyte* buffer; + GLint swapbytes, lsbfirst, rowlength; + GLint skiprows, skippixels, alignment; + GLenum format; + int size; + + if (inColor) { + format = GL_RGB; + size = width*height*3; + } else { + format = GL_LUMINANCE; + size = width*height*1; + } + + buffer = new GLubyte[size]; + if (buffer == NULL) + return NULL; + + glGetIntegerv (GL_UNPACK_SWAP_BYTES, &swapbytes); + glGetIntegerv (GL_UNPACK_LSB_FIRST, &lsbfirst); + glGetIntegerv (GL_UNPACK_ROW_LENGTH, &rowlength); + + glGetIntegerv (GL_UNPACK_SKIP_ROWS, &skiprows); + glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &skippixels); + glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment); + + glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE); + glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); + + glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + + glReadBuffer(GL_FRONT); + glReadPixels (0, 0, (GLsizei)width, (GLsizei)height, format, GL_UNSIGNED_BYTE, (GLvoid*) buffer); + + glPixelStorei (GL_UNPACK_SWAP_BYTES, swapbytes); + glPixelStorei (GL_UNPACK_LSB_FIRST, lsbfirst); + glPixelStorei (GL_UNPACK_ROW_LENGTH, rowlength); + + glPixelStorei (GL_UNPACK_SKIP_ROWS, skiprows); + glPixelStorei (GL_UNPACK_SKIP_PIXELS, skippixels); + glPixelStorei (GL_UNPACK_ALIGNMENT, alignment); + + return buffer; +} + +bool G4OpenGLViewer::printEPS() { + bool res; + + // Change the LC_NUMERIC value in order to have "." separtor and not "," + // This case is only useful for French, Canadien... + size_t len = strlen(setlocale(LC_NUMERIC,NULL)); + char* oldLocale = (char*)(malloc(len+1)); + if(oldLocale!=NULL) strncpy(oldLocale,setlocale(LC_NUMERIC,NULL),len); + setlocale(LC_NUMERIC,"C"); + + if (((fExportImageFormat == "eps") || (fExportImageFormat == "ps")) && (!fVectoredPs)) { + res = printNonVectoredEPS(); + } else { + res = printVectoredEPS(); + } + + // restore the local + if (oldLocale) { + setlocale(LC_NUMERIC,oldLocale); + free(oldLocale); + } + + if (res == false) { + G4cerr << "Error saving file... " << getRealPrintFilename().c_str() << G4endl; + } else { + G4cout << "File " << getRealPrintFilename().c_str() << " size: " << getRealExportWidth() << "x" << getRealExportHeight() << " has been saved " << G4endl; + + // increment index if necessary + if ( fExportFilenameIndex != -1) { + fExportFilenameIndex++; + } + } + + return res; +} + +bool G4OpenGLViewer::printVectoredEPS() { + return printGl2PS(); +} + +bool G4OpenGLViewer::printNonVectoredEPS () { + + int width = getRealExportWidth(); + int height = getRealExportHeight(); + + FILE* fp; + GLubyte* pixels; + GLubyte* curpix; + int components, pos, i; + + pixels = grabPixels (fPrintColour, width, height); + + if (pixels == NULL) { + G4cerr << "Failed to get pixels from OpenGl viewport" << G4endl; + return false; + } + if (fPrintColour) { + components = 3; + } else { + components = 1; + } + std::string name = getRealPrintFilename(); + fp = fopen (name.c_str(), "w"); + if (fp == NULL) { + G4cerr << "Can't open filename " << name.c_str() << G4endl; + return false; + } + + fprintf (fp, "%%!PS-Adobe-2.0 EPSF-1.2\n"); + fprintf (fp, "%%%%Title: %s\n", name.c_str()); + fprintf (fp, "%%%%Creator: OpenGL pixmap render output\n"); + fprintf (fp, "%%%%BoundingBox: 0 0 %d %d\n", width, height); + fprintf (fp, "%%%%EndComments\n"); + fprintf (fp, "gsave\n"); + fprintf (fp, "/bwproc {\n"); + fprintf (fp, " rgbproc\n"); + fprintf (fp, " dup length 3 idiv string 0 3 0 \n"); + fprintf (fp, " 5 -1 roll {\n"); + fprintf (fp, " add 2 1 roll 1 sub dup 0 eq\n"); + fprintf (fp, " { pop 3 idiv 3 -1 roll dup 4 -1 roll dup\n"); + fprintf (fp, " 3 1 roll 5 -1 roll } put 1 add 3 0 \n"); + fprintf (fp, " { 2 1 roll } ifelse\n"); + fprintf (fp, " }forall\n"); + fprintf (fp, " pop pop pop\n"); + fprintf (fp, "} def\n"); + fprintf (fp, "systemdict /colorimage known not {\n"); + fprintf (fp, " /colorimage {\n"); + fprintf (fp, " pop\n"); + fprintf (fp, " pop\n"); + fprintf (fp, " /rgbproc exch def\n"); + fprintf (fp, " { bwproc } image\n"); + fprintf (fp, " } def\n"); + fprintf (fp, "} if\n"); + fprintf (fp, "/picstr %d string def\n", width * components); + fprintf (fp, "%d %d scale\n", width, height); + fprintf (fp, "%d %d %d\n", width, height, 8); + fprintf (fp, "[%d 0 0 %d 0 0]\n", width, height); + fprintf (fp, "{currentfile picstr readhexstring pop}\n"); + fprintf (fp, "false %d\n", components); + fprintf (fp, "colorimage\n"); + + curpix = (GLubyte*) pixels; + pos = 0; + for (i = width*height*components; i>0; i--) { + fprintf (fp, "%02hx ", (unsigned short)(*(curpix++))); + if (++pos >= 32) { + fprintf (fp, "\n"); + pos = 0; + } + } + if (pos) + fprintf (fp, "\n"); + + fprintf (fp, "grestore\n"); + fprintf (fp, "showpage\n"); + delete [] pixels; + fclose (fp); + + // Reset for next time (useful is size change) + // fPrintSizeX = -1; + // fPrintSizeY = -1; + + return true; +} + +/** Return if gl2ps is currently writing + */ +bool G4OpenGLViewer::isGl2psWriting() { + + if (!fGL2PSAction) return false; + if (fGL2PSAction->fileWritingEnabled()) { + return true; + } + return false; +} + + +G4bool G4OpenGLViewer::isFramebufferReady() { + bool check = false; +#ifdef G4VIS_BUILD_OPENGLQT_DRIVER + check = true; +#endif +#ifdef G4VIS_BUILD_OPENGLX_DRIVER + check = false; +#endif +#ifdef G4VIS_BUILD_OPENGLXM_DRIVER + check = false; +#endif +#ifdef G4VIS_BUILD_OPENGLWIN32_DRIVER + check = false; +#endif + +#if GL_ARB_framebuffer_object + if (check) { +// if ( glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_UNDEFINED) { +// return false; +// } + } +#endif + return true; +} + + +/* Draw Gl2Ps text if needed + */ +void G4OpenGLViewer::DrawText(const G4Text& g4text) +{ + // gl2ps or GL window ? + if (isGl2psWriting()) { + + G4VSceneHandler::MarkerSizeType sizeType; + G4double size = fSceneHandler.GetMarkerSize(g4text,sizeType); + G4Point3D position = g4text.GetPosition(); + + G4String textString = g4text.GetText(); + + glRasterPos3d(position.x(),position.y(),position.z()); + GLint align = GL2PS_TEXT_B; + + switch (g4text.GetLayout()) { + case G4Text::left: align = GL2PS_TEXT_BL; break; + case G4Text::centre: align = GL2PS_TEXT_B; break; + case G4Text::right: align = GL2PS_TEXT_BR; + } + + gl2psTextOpt(textString.c_str(),"Times-Roman",GLshort(size),align,0); + + } else { + + static G4int callCount = 0; + ++callCount; + //if (callCount <= 10 || callCount%100 == 0) { + if (callCount <= 1) { + G4cout << + "G4OpenGLViewer::DrawText: Not implemented for \"" + << fName << + "\"\n Called with " + << g4text + << G4endl; + } + } +} + +/** Change PointSize on gl2ps if needed + */ +void G4OpenGLViewer::ChangePointSize(G4double size) { + + if (isGl2psWriting()) { + fGL2PSAction->setPointSize(int(size)); + } else { + glPointSize (size); + } +} + + +/** Change LineSize on gl2ps if needed + */ +void G4OpenGLViewer::ChangeLineWidth(G4double width) { + + if (isGl2psWriting()) { + fGL2PSAction->setLineWidth(int(width)); + } else { + glLineWidth (width); + } +} + +/** + Export image with the given name with width and height + Several cases : + If name is "", filename will have the default value + If name is "toto.png", set the name to "toto" and the format to "png". No incremented suffix is added. + If name is "toto", set the name to "toto" and the format to default (or current format if specify). + Will also add an incremented suffix at the end of the file +*/ +bool G4OpenGLViewer::exportImage(std::string name, int width, int height) { + + if (! setExportFilename(name)) { + return false; + } + + if ((width != -1) && (height != -1)) { + setExportSize(width, height); + } + + if (fExportImageFormat == "eps") { + fGL2PSAction->setExportImageFormat(GL2PS_EPS); + } else if (fExportImageFormat == "ps") { + fGL2PSAction->setExportImageFormat(GL2PS_PS); + } else if (fExportImageFormat == "svg") { + fGL2PSAction->setExportImageFormat(GL2PS_SVG); + } else if (fExportImageFormat == "pdf") { + fGL2PSAction->setExportImageFormat(GL2PS_PDF); + } else { + setExportImageFormat(fExportImageFormat,true); // will display a message if this format is not correct for the current viewer + return false; + } + return printEPS(); +} + + +bool G4OpenGLViewer::printGl2PS() { + + int width = getRealExportWidth(); + int height = getRealExportHeight(); + bool res = true; + + // no need to redraw at each new primitive for printgl2PS + G4OpenGLSceneHandler& oglSceneHandler = dynamic_cast(fSceneHandler); + G4OpenGLSceneHandler::FlushAction originalFlushAction = oglSceneHandler.GetFlushAction(); + oglSceneHandler.SetFlushAction(G4OpenGLSceneHandler::never); + + if (!fGL2PSAction) return false; + + fGL2PSAction->setFileName(getRealPrintFilename().c_str()); + // try to resize + int X = fWinSize_x; + int Y = fWinSize_y; + + fWinSize_x = width; + fWinSize_y = height; + // Laurent G. 16/03/10 : Not the good way to do. + // We should draw in a new offscreen context instead of + // resizing and drawing in current window... + // This should be solve when we will do an offscreen method + // to render OpenGL + // See : + // http://developer.apple.com/Mac/library/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_offscreen/opengl_offscreen.html + // http://www.songho.ca/opengl/gl_fbo.html + + ResizeGLView(); + bool extendBuffer = true; + bool endWriteAction = false; + bool beginWriteAction = true; + bool filePointerOk = true; + while ((extendBuffer) && (! endWriteAction) && (filePointerOk)) { + + beginWriteAction = fGL2PSAction->enableFileWriting(); + // 3 cases : + // - true + // - false && ! fGL2PSAction->fileWritingEnabled() => bad file name + // - false && fGL2PSAction->fileWritingEnabled() => buffer size problem ? + + filePointerOk = fGL2PSAction->fileWritingEnabled(); + + if (beginWriteAction) { + + // Set the viewport + // By default, we choose the line width (trajectories...) + fGL2PSAction->setLineWidth(fGl2psDefaultLineWith); + // By default, we choose the point size (markers...) + fGL2PSAction->setPointSize(fGl2psDefaultPointSize); + + DrawView (); + endWriteAction = fGL2PSAction->disableFileWriting(); + } + if (filePointerOk) { + if ((! endWriteAction) || (! beginWriteAction)) { + extendBuffer = fGL2PSAction->extendBufferSize(); + } + } + } + fGL2PSAction->resetBufferSizeParameters(); + + if (!extendBuffer ) { + G4cerr << "ERROR: gl2ps buffer size is not big enough to print this geometry. Try to extend it. No output produced"<< G4endl; + res = false; + } + if (!beginWriteAction ) { + G4cerr << "ERROR: saving file "< dims[0]){ + return dims[0]; + } + } + if (fPrintSizeX < -1){ + return 0; + } + return fPrintSizeX; +} + +G4int G4OpenGLViewer::getRealExportHeight() { + if (fPrintSizeY == -1) { + return fWinSize_y; + } + GLint dims[2]; + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims); + + // L.Garnier 01-2010: Some problems with mac 10.6 + if ((dims[0] !=0 ) && (dims[1] !=0)) { + if (fPrintSizeY > dims[1]){ + return dims[1]; + } + } + if (fPrintSizeY < -1){ + return 0; + } + return fPrintSizeY; +} + +void G4OpenGLViewer::setExportSize(G4int X, G4int Y) { + fPrintSizeX = X; + fPrintSizeY = Y; +} + +/** + If name is "" or "!", filename and extension will have the default value. + If name is "toto.png", set the name to "toto" and the format to "png". No incremented suffix is added. + If name is "toto", set the name to "toto" and the format to default (or current format if specify). + If name is the same as previous, do not reset incremented suffix. +*/ +bool G4OpenGLViewer::setExportFilename(G4String name,G4bool inc) { + if (name == "!") { + name = ""; + } + + if (inc) { + if ((name != "") && (fExportFilename != name)) { + fExportFilenameIndex=0; + } + } else { + fExportFilenameIndex=-1; + } + + if (name.size() == 0) { + name = getRealPrintFilename().c_str(); + } else { + // guess format by extention + std::string extension = name.substr(name.find_last_of(".") + 1); + // no format + if (name.size() != extension.size()) { + if (! setExportImageFormat(extension, false)) { + return false; + } + } + // get the name + fExportFilename = name.substr(0,name.find_last_of(".")); + } + return true; +} + +std::string G4OpenGLViewer::getRealPrintFilename() { + std::string temp = fExportFilename; + if (fExportFilenameIndex != -1) { + temp += std::string("_"); + std::ostringstream os; + os << std::setw(4) << std::setfill('0') << fExportFilenameIndex; + std::string nb_str = os.str(); + temp += nb_str; + } + temp += "."+fExportImageFormat; + return temp; +} + +GLdouble G4OpenGLViewer::getSceneNearWidth() +{ + if (!fSceneHandler.GetScene()) { + return 0; + } + const G4Point3D targetPoint + = fSceneHandler.GetScene()->GetStandardTargetPoint() + + fVP.GetCurrentTargetPoint (); + G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius(); + if(radius<=0.) radius = 1.; + const G4double cameraDistance = fVP.GetCameraDistance (radius); + const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius); + return 2 * fVP.GetFrontHalfHeight (pnear, radius); +} + +GLdouble G4OpenGLViewer::getSceneFarWidth() +{ + if (!fSceneHandler.GetScene()) { + return 0; + } + const G4Point3D targetPoint + = fSceneHandler.GetScene()->GetStandardTargetPoint() + + fVP.GetCurrentTargetPoint (); + G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius(); + if(radius<=0.) radius = 1.; + const G4double cameraDistance = fVP.GetCameraDistance (radius); + const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius); + const GLdouble pfar = fVP.GetFarDistance (cameraDistance, pnear, radius); + return 2 * fVP.GetFrontHalfHeight (pfar, radius); +} + + +GLdouble G4OpenGLViewer::getSceneDepth() +{ + if (!fSceneHandler.GetScene()) { + return 0; + } + const G4Point3D targetPoint + = fSceneHandler.GetScene()->GetStandardTargetPoint() + + fVP.GetCurrentTargetPoint (); + G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius(); + if(radius<=0.) radius = 1.; + const G4double cameraDistance = fVP.GetCameraDistance (radius); + const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius); + return fVP.GetFarDistance (cameraDistance, pnear, radius)- pnear; +} + + + +void G4OpenGLViewer::rotateScene(G4double dx, G4double dy) +{ + if (fVP.GetRotationStyle() == G4ViewParameters::freeRotation) { + rotateSceneInViewDirection(dx,dy); + } else { + if( dx != 0) { + rotateSceneThetaPhi(dx,0); + } + if( dy != 0) { + rotateSceneThetaPhi(0,dy); + } + } +} + + +void G4OpenGLViewer::rotateSceneToggle(G4double dx, G4double dy) +{ + if (fVP.GetRotationStyle() != G4ViewParameters::freeRotation) { + rotateSceneInViewDirection(dx,dy); + } else { + if( dx != 0) { + rotateSceneThetaPhi(dx,0); + } + if( dy != 0) { + rotateSceneThetaPhi(0,dy); + } + } +} + +void G4OpenGLViewer::rotateSceneThetaPhi(G4double dx, G4double dy) +{ + if (!fSceneHandler.GetScene()) { + return; + } + + G4Vector3D vp; + G4Vector3D up; + + G4Vector3D xprime; + G4Vector3D yprime; + G4Vector3D zprime; + + G4double delta_alpha; + G4double delta_theta; + + G4Vector3D new_vp; + G4Vector3D new_up; + + G4double cosalpha; + G4double sinalpha; + + G4Vector3D a1; + G4Vector3D a2; + G4Vector3D delta; + G4Vector3D viewPoint; + + + //phi spin stuff here + + vp = fVP.GetViewpointDirection ().unit (); + up = fVP.GetUpVector ().unit (); + + yprime = (up.cross(vp)).unit(); + zprime = (vp.cross(yprime)).unit(); + + if (fVP.GetLightsMoveWithCamera()) { + delta_alpha = dy * fRot_sens; + delta_theta = -dx * fRot_sens; + } else { + delta_alpha = -dy * fRot_sens; + delta_theta = dx * fRot_sens; + } + + delta_alpha *= deg; + delta_theta *= deg; + + new_vp = std::cos(delta_alpha) * vp + std::sin(delta_alpha) * zprime; + + // to avoid z rotation flipping + // to allow more than 360∞ rotation + + if (fVP.GetLightsMoveWithCamera()) { + new_up = (new_vp.cross(yprime)).unit(); + if (new_vp.z()*vp.z() <0) { + new_up.set(new_up.x(),-new_up.y(),new_up.z()); + } + } else { + new_up = up; + if (new_vp.z()*vp.z() <0) { + new_up.set(new_up.x(),-new_up.y(),new_up.z()); + } + } + fVP.SetUpVector(new_up); + //////////////// + // Rotates by fixed azimuthal angle delta_theta. + + cosalpha = new_up.dot (new_vp.unit()); + sinalpha = std::sqrt (1. - std::pow (cosalpha, 2)); + yprime = (new_up.cross (new_vp.unit())).unit (); + xprime = yprime.cross (new_up); + // Projection of vp on plane perpendicular to up... + a1 = sinalpha * xprime; + // Required new projection... + a2 = sinalpha * (std::cos (delta_theta) * xprime + std::sin (delta_theta) * yprime); + // Required Increment vector... + delta = a2 - a1; + // So new viewpoint is... + viewPoint = new_vp.unit() + delta; + + fVP.SetViewAndLights (viewPoint); +} + + +void G4OpenGLViewer::rotateSceneInViewDirection(G4double dx, G4double dy) +{ + if (!fSceneHandler.GetScene()) { + return; + } + + G4Vector3D vp; + G4Vector3D up; + + G4Vector3D xprime; + G4Vector3D yprime; + G4Vector3D zprime; + + G4Vector3D new_vp; + G4Vector3D new_up; + + G4Vector3D a1; + G4Vector3D a2; + G4Vector3D delta; + G4Vector3D viewPoint; + + dx = dx/100; + dy = dy/100; + + //phi spin stuff here + + vp = fVP.GetViewpointDirection ().unit(); + up = fVP.GetUpVector ().unit(); + + G4Vector3D zPrimeVector = G4Vector3D(up.y()*vp.z()-up.z()*vp.y(), + up.z()*vp.x()-up.x()*vp.z(), + up.x()*vp.y()-up.y()*vp.x()); + + viewPoint = vp/fRot_sens + (zPrimeVector*dx - up*dy) ; + new_up = G4Vector3D(viewPoint.y()*zPrimeVector.z()-viewPoint.z()*zPrimeVector.y(), + viewPoint.z()*zPrimeVector.x()-viewPoint.x()*zPrimeVector.z(), + viewPoint.x()*zPrimeVector.y()-viewPoint.y()*zPrimeVector.x()); + + G4Vector3D new_upUnit = new_up.unit(); + + + + fVP.SetUpVector(new_upUnit); + fVP.SetViewAndLights (viewPoint); +} + + +void G4OpenGLViewer::addExportImageFormat(std::string format) { + fExportImageFormatVector.push_back(format); +} + +bool G4OpenGLViewer::setExportImageFormat(std::string format, bool quiet) { + bool found = false; + std::string list; + for (unsigned int a=0; a(fSceneHandler); + sh.setVboDrawer(fVboDrawer); + } catch(std::bad_cast exp) { } +} + +#endif + + +G4String G4OpenGLViewerPickMap::print() { + std::ostringstream txt; + +#ifdef LAYERED_GEOMETRY_PICKING_EXTENSIONS + G4TransportationManager *tmanager = + G4TransportationManager::GetTransportationManager(); + std::vector::iterator iter = + tmanager->GetWorldsIterator(); + G4FieldManager *fieldmgr = 0; + bool warning = false; + bool seen = false; + for (int world = tmanager->GetNoWorlds() - 1; world >= 0; --world) { + G4Navigator *navigator = tmanager->GetNavigator(iter[world]); + G4VPhysicalVolume *pvol = navigator-> + LocateGlobalPointAndSetup(fCoordinates,0,false); + if (!pvol) + continue; + G4LogicalVolume *lvol = pvol->GetLogicalVolume(); + if (!lvol) + continue; + G4Material *mat = lvol->GetMaterial(); + if (fieldmgr == 0) { + fieldmgr = lvol->GetFieldManager(); + } + else if (fieldmgr != lvol->GetFieldManager()) { + txt << "ERROR - field manager inconsistency found in world " << world + << std::endl; + warning = true; + } + if (warning || (mat != 0 && !seen)) { + G4TouchableHistory *hist = navigator->CreateTouchableHistory(); + std::ostringstream pvpath; + pvpath << "/" << navigator->GetWorldVolume()->GetName() << ":0"; + for (int depth = hist->GetHistoryDepth() - 1; depth >= 0; --depth) { + pvpath << "/" << hist->GetVolume(depth)->GetName() + << ":" << hist->GetVolume(depth)->GetCopyNo(); + } + + txt << "(" << fCoordinates[0] / cm + << "," << fCoordinates[1] / cm + << "," << fCoordinates[2] / cm << ")" + << " found in " << pvol->GetName() << " copy " << pvol->GetCopyNo() + << " of " << lvol->GetName() << " with " << std::endl + << " complete path: " << pvpath.str() << std::endl + << " layer " << world << " material: " + << ((mat)? mat->GetName() : "0") << std::endl; + if (fieldmgr) { + const G4Field *fld = fieldmgr->GetDetectorField(); + if (fld) { + double Bfld[3]; + double xglob[4] = {fCoordinates[0],fCoordinates[1],fCoordinates[2],0}; + fld->GetFieldValue(xglob,Bfld); + txt << " magnetic field (Tesla): " + << Bfld[0] / tesla << "," + << Bfld[1] / tesla << "," + << Bfld[2] / tesla << std::endl; + } + else { + txt << " magnetic field: UNDEFINED" << std::endl; + } + } + else { + txt << " magnetic field: null" << std::endl; + } + seen = true; + } + } + +#else + for (unsigned int a=0; a getAttributes() { + return fAttributes; + } + + G4String print(); + + private : + G4String fName; + G4int fHitNumber; + G4int fSubHitNumber; + G4int fPickName; + std::vector fAttributes; +#ifdef LAYERED_GEOMETRY_PICKING_EXTENSIONS + G4ThreeVector fCoordinates; +#endif + +}; + +// Base class for various OpenGLView classes. +class G4OpenGLViewer: virtual public G4VViewer { + + friend class G4OpenGLSceneHandler; + friend class G4OpenGLImmediateSceneHandler; + friend class G4OpenGLStoredSceneHandler; + friend class G4OpenGLFileSceneHandler; + friend class G4OpenGLViewerMessenger; + +public: + void ClearView (); + void ClearViewWithoutFlush (); +//////////////////////////////Vectored PostScript production functions/// + bool printEPS(); + virtual bool exportImage(std::string name="", int width=-1, int height=-1); + + bool setExportImageFormat(std::string format,bool quiet = false); + // change the export image format according to thoses available for the current viewer + + // Special case for Wt, we want to have acces to the drawer +#ifdef G4OPENGL_VERSION_2 + inline G4OpenGLVboDrawer* getWtDrawer() {return fVboDrawer;} + + // Associate the Wt drawer to the OpenGLViewer and the OpenGLSceneHandler + void setVboDrawer(G4OpenGLVboDrawer* drawer); + G4OpenGLVboDrawer* fVboDrawer; + + inline bool isInitialized() { + return fGlViewInitialized; + } +#endif + +protected: + G4OpenGLViewer (G4OpenGLSceneHandler& scene); + virtual ~G4OpenGLViewer (); + +private: + G4OpenGLViewer(const G4OpenGLViewer&); + G4OpenGLViewer& operator= (const G4OpenGLViewer&); + +protected: + void SetView (); + void ResetView (); + + virtual void DrawText(const G4Text&); + void ChangePointSize(G4double size); + void ChangeLineWidth(G4double width); + void HaloingFirstPass (); + void HaloingSecondPass (); + void HLRFirstPass (); + void HLRSecondPass (); + void HLRThirdPass (); + void InitializeGLView (); + void ResizeGLView(); + void ResizeWindow(unsigned int, unsigned int); + virtual G4String Pick(GLdouble x, GLdouble y); + const std::vector < G4OpenGLViewerPickMap* > & GetPickDetails(GLdouble x, GLdouble y); + virtual void CreateFontLists () {} + void rotateScene (G4double dx, G4double dy); + void rotateSceneToggle (G4double dx, G4double dy); +//////////////////////////////Vectored PostScript production functions/// + // print EPS file. Depending of fVectoredPs, it will print Vectored or not + void setExportSize(G4int,G4int); + // set the new print size. + // -1 means 'print size' = 'window size' + // Setting size greater than max OpenGL viewport size will set the size to + // maximum + bool setExportFilename(G4String name,G4bool inc = true); + // set export filename. + // if inc, then the filename will be increment by one each time + // try to guesss the correct format according to the extention + + std::string getRealPrintFilename(); + unsigned int getWinWidth() const; + unsigned int getWinHeight() const; + G4bool sizeHasChanged(); + // return true if size has change since last redraw + GLdouble getSceneNearWidth(); + GLdouble getSceneFarWidth(); + GLdouble getSceneDepth(); + void addExportImageFormat(std::string format); + // add a image format to the available export format list + G4bool isGl2psWriting(); + G4bool isFramebufferReady(); + + void g4GluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height, + GLint viewport[4]); + // MESA implementation of gluPickMatrix + + void g4GluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez, + GLdouble centerx, GLdouble centery, GLdouble + centerz, + GLdouble upx, GLdouble upy, GLdouble upz ); + // MESA implementation of gluLookAt + void g4GlOrtho (GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top, + GLdouble near, GLdouble far); + // Redefinition on glOrtho to solve precision issues + void g4GlFrustum (GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top, + GLdouble near, GLdouble far); + // Redefinition on glFrustum to solve precision issues + + G4bool fPrintColour; + G4bool fVectoredPs; + + G4OpenGLSceneHandler& fOpenGLSceneHandler; + G4Colour background; //the OpenGL clear colour + G4bool + transparency_enabled, //is alpha blending enabled? + antialiasing_enabled, //is antialiasing enabled? + haloing_enabled; //is haloing enabled for wireframe? + G4double fStartTime, fEndTime; // Time range (e.g., for trajectory steps). + G4double fFadeFactor; // 0: no fade; 1: maximum fade with time within range. + G4bool fDisplayHeadTime; // Display head time (fEndTime) in 2D text. + G4double fDisplayHeadTimeX, fDisplayHeadTimeY; // 2D screen coords. + G4double fDisplayHeadTimeSize; // Screen size. + G4double fDisplayHeadTimeRed, fDisplayHeadTimeGreen, fDisplayHeadTimeBlue; + G4bool fDisplayLightFront;// Display light front at head time originating at + G4double fDisplayLightFrontX, fDisplayLightFrontY, fDisplayLightFrontZ, + fDisplayLightFrontT; + G4double fDisplayLightFrontRed, fDisplayLightFrontGreen, fDisplayLightFrontBlue; + G4OpenGL2PSAction* fGL2PSAction; + + G4double fRot_sens; // Rotation sensibility in degrees + G4double fPan_sens; // Translation sensibility + unsigned int fWinSize_x; + unsigned int fWinSize_y; + std::vector < std::string > fExportImageFormatVector; + std::string fDefaultExportImageFormat; + std::string fExportImageFormat; + int fExportFilenameIndex; + G4int fPrintSizeX; + G4int fPrintSizeY; + + +private : + G4float fPointSize; + G4String fExportFilename; + G4String fDefaultExportFilename; + G4bool fSizeHasChanged; + int fGl2psDefaultLineWith; + int fGl2psDefaultPointSize; + bool fGlViewInitialized; + + // size of the OpenGL frame + void rotateSceneThetaPhi(G4double dx, G4double dy); + void rotateSceneInViewDirection (G4double dx, G4double dy); + bool printGl2PS(); + G4int getRealExportWidth(); + G4int getRealExportHeight(); + GLubyte* grabPixels (int inColor, + unsigned int width, + unsigned int height); + bool printNonVectoredEPS (); + // print non vectored EPS files + + bool printVectoredEPS(); + // print vectored EPS files + + bool fIsGettingPickInfos; + // Block SetView() during picking + +#ifdef G4OPENGL_VERSION_2 +public: +#ifdef G4VIS_BUILD_OPENGLWT_DRIVER + inline Wt::WGLWidget::Program getShaderProgram() { + return fShaderProgram; + } + inline Wt::WGLWidget::UniformLocation getShaderProjectionMatrix() { + return fpMatrixUniform; + } + inline Wt::WGLWidget::UniformLocation getShaderTransformMatrix() { + return ftMatrixUniform; + } +#else + inline GLuint getShaderProgram() { + return fShaderProgram; + } + inline GLuint getShaderProjectionMatrix() { + return fpMatrixUniform; + } + inline GLuint getShaderTransformMatrix() { + return ftMatrixUniform; + } + inline GLuint getShaderViewModelMatrix() { + return fmvMatrixUniform; + } +#endif + +protected : + + // define the keyword shader to handle it in a better way for OpenGL and WebGL +#ifdef G4VIS_BUILD_OPENGLWT_DRIVER +#define Shader Wt::WGLWidget::Shader +#else +#define Shader GLuint +#endif + + // define some attributes and variables for OpenGL and WebGL +#ifdef G4VIS_BUILD_OPENGLWT_DRIVER + Wt::WGLWidget::Program fShaderProgram; + + // Program and related variables + Wt::WGLWidget::AttribLocation fVertexPositionAttribute; + Wt::WGLWidget::AttribLocation fVertexNormalAttribute; + Wt::WGLWidget::UniformLocation fpMatrixUniform; + Wt::WGLWidget::UniformLocation fcMatrixUniform; + Wt::WGLWidget::UniformLocation fmvMatrixUniform; + Wt::WGLWidget::UniformLocation fnMatrixUniform; + Wt::WGLWidget::UniformLocation ftMatrixUniform; +#else + GLuint fShaderProgram; + + // Program and related variables + GLuint fVertexPositionAttribute; + GLuint fVertexNormalAttribute; + GLuint fpMatrixUniform; + GLuint fcMatrixUniform; + GLuint fmvMatrixUniform; + GLuint fnMatrixUniform; + GLuint ftMatrixUniform; +#endif + +#endif +}; + +#endif + +#endif diff --git a/src/G4.10.04.p02fixes/G4ParallelWorldProcess.cc b/src/G4.10.04.p02fixes/G4ParallelWorldProcess.cc new file mode 100644 index 0000000..c607227 --- /dev/null +++ b/src/G4.10.04.p02fixes/G4ParallelWorldProcess.cc @@ -0,0 +1,455 @@ +// +// ******************************************************************** +// * 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: G4ParallelWorldProcess.cc 103731 2017-04-25 08:01:05Z gcosmo $ +// GEANT4 tag $Name: geant4-09-04-ref-00 $ +// +// + +#include "G4ios.hh" +#include "G4ParallelWorldProcess.hh" +#include "G4ParallelWorldProcessStore.hh" +#include "G4Step.hh" +#include "G4StepPoint.hh" +#include "G4Navigator.hh" +#include "G4VTouchable.hh" +#include "G4VPhysicalVolume.hh" +#include "G4ParticleChange.hh" +#include "G4PathFinder.hh" +#include "G4TransportationManager.hh" +#include "G4ParticleChange.hh" +#include "G4StepPoint.hh" +#include "G4FieldTrackUpdator.hh" +#include "G4Material.hh" +#include "G4ProductionCuts.hh" +#include "G4ProductionCutsTable.hh" + +#include "G4SDManager.hh" +#include "G4VSensitiveDetector.hh" + +G4ThreadLocal G4Step* G4ParallelWorldProcess::fpHyperStep = 0; +G4ThreadLocal G4int G4ParallelWorldProcess::nParallelWorlds = 0; +G4ThreadLocal G4int G4ParallelWorldProcess::fNavIDHyp = 0; +const G4Step* G4ParallelWorldProcess::GetHyperStep() +{ return fpHyperStep; } +G4int G4ParallelWorldProcess::GetHypNavigatorID() +{ return fNavIDHyp; } + +G4ParallelWorldProcess:: +G4ParallelWorldProcess(const G4String& processName,G4ProcessType theType) +:G4VProcess(processName,theType),fGhostWorld(nullptr),fGhostNavigator(nullptr), + fNavigatorID(-1),fFieldTrack('0'),fGhostSafety(0.),fOnBoundary(false), + layeredMaterialFlag(false) +{ + SetProcessSubType(491); + if(!fpHyperStep) fpHyperStep = new G4Step(); + iParallelWorld = ++nParallelWorlds; + + pParticleChange = &aDummyParticleChange; + + fGhostStep = new G4Step(); + fGhostPreStepPoint = fGhostStep->GetPreStepPoint(); + fGhostPostStepPoint = fGhostStep->GetPostStepPoint(); + + fTransportationManager = G4TransportationManager::GetTransportationManager(); + fTransportationManager->GetNavigatorForTracking()->SetPushVerbosity(false); + fPathFinder = G4PathFinder::GetInstance(); + + fGhostWorldName = "** NotDefined **"; + G4ParallelWorldProcessStore::GetInstance()->SetParallelWorld(this,processName); + + if (verboseLevel>0) + { + G4cout << GetProcessName() << " is created " << G4endl; + } +} + +G4ParallelWorldProcess::~G4ParallelWorldProcess() +{ + delete fGhostStep; + nParallelWorlds--; + if(nParallelWorlds==0) + { + delete fpHyperStep; + fpHyperStep = 0; + } +} + +void G4ParallelWorldProcess:: +SetParallelWorld(G4String parallelWorldName) +{ + fGhostWorldName = parallelWorldName; + fGhostWorld = fTransportationManager->GetParallelWorld(fGhostWorldName); + fGhostNavigator = fTransportationManager->GetNavigator(fGhostWorld); + fGhostNavigator->SetPushVerbosity(false); +} + +void G4ParallelWorldProcess:: +SetParallelWorld(G4VPhysicalVolume* parallelWorld) +{ + fGhostWorldName = parallelWorld->GetName(); + fGhostWorld = parallelWorld; + fGhostNavigator = fTransportationManager->GetNavigator(fGhostWorld); + fGhostNavigator->SetPushVerbosity(false); +} + +void G4ParallelWorldProcess::StartTracking(G4Track* trk) +{ + if(fGhostNavigator) + { fNavigatorID = fTransportationManager->ActivateNavigator(fGhostNavigator); } + else + { + G4Exception("G4ParallelWorldProcess::StartTracking", + "ProcParaWorld000",FatalException, + "G4ParallelWorldProcess is used for tracking without having a parallel world assigned"); + } + fPathFinder->PrepareNewTrack(trk->GetPosition(),trk->GetMomentumDirection()); + + fOldGhostTouchable = fPathFinder->CreateTouchableHandle(fNavigatorID); + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fNewGhostTouchable = fOldGhostTouchable; + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + + fGhostSafety = -1.; + fOnBoundary = false; + fGhostPreStepPoint->SetStepStatus(fUndefined); + fGhostPostStepPoint->SetStepStatus(fUndefined); + +// G4VPhysicalVolume* thePhys = fNewGhostTouchable->GetVolume(); +// if(thePhys) +// { +// G4Material* ghostMaterial = thePhys->GetLogicalVolume()->GetMaterial(); +// if(ghostMaterial) +// { G4cout << " --- Material : " << ghostMaterial->GetName() << G4endl; } +// } + + *(fpHyperStep->GetPostStepPoint()) = *(trk->GetStep()->GetPostStepPoint()); + if(layeredMaterialFlag) + { + G4StepPoint* realWorldPostStepPoint = trk->GetStep()->GetPostStepPoint(); + SwitchMaterial(realWorldPostStepPoint); + G4StepPoint *realWorldPreStepPoint = trk->GetStep()->GetPreStepPoint(); + SwitchMaterial(realWorldPreStepPoint); + G4double velocity = trk->CalculateVelocity(); + realWorldPostStepPoint->SetVelocity(velocity); + realWorldPreStepPoint->SetVelocity(velocity); + trk->SetVelocity(velocity); + } + *(fpHyperStep->GetPreStepPoint()) = *(fpHyperStep->GetPostStepPoint()); +} + +G4double +G4ParallelWorldProcess::AtRestGetPhysicalInteractionLength( + const G4Track& /*track*/, + G4ForceCondition* condition) +{ +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// At Rest must be registered ONLY for the particle which has other At Rest +// process(es). +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + *condition = Forced; + return DBL_MAX; +} + +G4VParticleChange* G4ParallelWorldProcess::AtRestDoIt( + const G4Track& track, + const G4Step& step) +{ +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// At Rest must be registered ONLY for the particle which has other At Rest +// process(es). +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fOldGhostTouchable = fGhostPostStepPoint->GetTouchableHandle(); + G4VSensitiveDetector* aSD = 0; + if(fOldGhostTouchable->GetVolume()) + { aSD = fOldGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector(); } + fOnBoundary = false; + if(aSD) + { + CopyStep(step); + fGhostPreStepPoint->SetSensitiveDetector(aSD); + + fNewGhostTouchable = fOldGhostTouchable; + + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + if(fNewGhostTouchable->GetVolume()) + { + fGhostPostStepPoint->SetSensitiveDetector( + fNewGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector()); + } + else + { fGhostPostStepPoint->SetSensitiveDetector(0); } + + aSD->Hit(fGhostStep); + } + + pParticleChange->Initialize(track); + return pParticleChange; +} + +G4double +G4ParallelWorldProcess::PostStepGetPhysicalInteractionLength( + const G4Track& /*track*/, + G4double /*previousStepSize*/, + G4ForceCondition* condition) +{ + *condition = StronglyForced; + return DBL_MAX; +} + +G4VParticleChange* G4ParallelWorldProcess::PostStepDoIt( + const G4Track& track, + const G4Step& step) +{ + fOldGhostTouchable = fGhostPostStepPoint->GetTouchableHandle(); + G4VSensitiveDetector* aSD = 0; + if(fOldGhostTouchable->GetVolume()) + { aSD = fOldGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector(); } + CopyStep(step); + fGhostPreStepPoint->SetSensitiveDetector(aSD); + + if(fOnBoundary) + { + fNewGhostTouchable = fPathFinder->CreateTouchableHandle(fNavigatorID); + } + else + { + fNewGhostTouchable = fOldGhostTouchable; + } + + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + + if(fNewGhostTouchable->GetVolume()) + { + fGhostPostStepPoint->SetSensitiveDetector( + fNewGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector()); + } + else + { fGhostPostStepPoint->SetSensitiveDetector(0); } + + G4VSensitiveDetector* sd = fGhostPreStepPoint->GetSensitiveDetector(); + if(sd) + { + sd->Hit(fGhostStep); + } + + pParticleChange->Initialize(track); + if(layeredMaterialFlag) + { + G4StepPoint* realWorldPostStepPoint = + ((G4Step*)(track.GetStep()))->GetPostStepPoint(); + SwitchMaterial(realWorldPostStepPoint); + } + return pParticleChange; +} + +G4double G4ParallelWorldProcess::AlongStepGetPhysicalInteractionLength( + const G4Track& track, G4double previousStepSize, G4double currentMinimumStep, + G4double& proposedSafety, G4GPILSelection* selection) +{ + static G4ThreadLocal G4FieldTrack *endTrack_G4MT_TLS_ = 0 ; if (!endTrack_G4MT_TLS_) endTrack_G4MT_TLS_ = new G4FieldTrack ('0') ; G4FieldTrack &endTrack = *endTrack_G4MT_TLS_; + //static ELimited eLimited; + ELimited eLimited; + ELimited eLim = kUndefLimited; + + *selection = NotCandidateForSelection; + G4double returnedStep = DBL_MAX; + + if (previousStepSize > 0.) + { fGhostSafety -= previousStepSize; } + if (fGhostSafety < 0.) fGhostSafety = 0.0; + + if (currentMinimumStep <= fGhostSafety && currentMinimumStep > 0.) + { + // I have no chance to limit + returnedStep = currentMinimumStep; + fOnBoundary = false; + proposedSafety = fGhostSafety - currentMinimumStep; + eLim = kDoNot; + } + else + { + G4FieldTrackUpdator::Update(&fFieldTrack,&track); + +#ifdef G4DEBUG_PARALLEL_WORLD_PROCESS + if( verboseLevel > 0 ){ + int localVerb = verboseLevel-1; + + if( localVerb == 1 ) { + G4cout << " Pll Wrl proc::AlongStepGPIL " << this->GetProcessName() << G4endl; + }else if( localVerb > 1 ) { + G4cout << "----------------------------------------------" << G4endl; + G4cout << " ParallelWorldProcess: field Track set to : " << G4endl; + G4cout << "----------------------------------------------" << G4endl; + G4cout << fFieldTrack << G4endl; + G4cout << "----------------------------------------------" << G4endl; + } + } +#endif + + returnedStep + = fPathFinder->ComputeStep(fFieldTrack,currentMinimumStep,fNavigatorID, + track.GetCurrentStepNumber(),fGhostSafety,eLimited, + endTrack,track.GetVolume()); + if(eLimited == kDoNot) + { + fOnBoundary = false; + fGhostSafety = fGhostNavigator->ComputeSafety(endTrack.GetPosition()); + } + else + { + fOnBoundary = true; + // fGhostSafetyEnd = 0.0; // At end-point of expected step only + } + proposedSafety = fGhostSafety; + if(eLimited == kUnique || eLimited == kSharedOther) { + *selection = CandidateForSelection; + } + else if (eLimited == kSharedTransport) { + returnedStep *= (1.0 + 1.0e-9); + } + eLim = eLimited; + } + + if(iParallelWorld==nParallelWorlds) fNavIDHyp = 0; + if(eLim == kUnique || eLim == kSharedOther) fNavIDHyp = fNavigatorID; + return returnedStep; +} + +G4VParticleChange* G4ParallelWorldProcess::AlongStepDoIt( + const G4Track& track, const G4Step& ) +{ + pParticleChange->Initialize(track); + return pParticleChange; +} + +void G4ParallelWorldProcess::CopyStep(const G4Step & step) +{ + G4StepStatus prevStat = fGhostPostStepPoint->GetStepStatus(); + + fGhostStep->SetTrack(step.GetTrack()); + fGhostStep->SetStepLength(step.GetStepLength()); + fGhostStep->SetTotalEnergyDeposit(step.GetTotalEnergyDeposit()); + fGhostStep->SetNonIonizingEnergyDeposit(step.GetNonIonizingEnergyDeposit()); + fGhostStep->SetControlFlag(step.GetControlFlag()); + fGhostStep->SetSecondary((const_cast(step)).GetfSecondary()); + + *fGhostPreStepPoint = *(step.GetPreStepPoint()); + *fGhostPostStepPoint = *(step.GetPostStepPoint()); + + fGhostPreStepPoint->SetStepStatus(prevStat); + if(fOnBoundary) + { fGhostPostStepPoint->SetStepStatus(fGeomBoundary); } + else if(fGhostPostStepPoint->GetStepStatus()==fGeomBoundary) + { fGhostPostStepPoint->SetStepStatus(fPostStepDoItProc); } + + if(iParallelWorld==1) + { + G4StepStatus prevStatHyp = fpHyperStep->GetPostStepPoint()->GetStepStatus(); + + fpHyperStep->SetTrack(step.GetTrack()); + fpHyperStep->SetStepLength(step.GetStepLength()); + fpHyperStep->SetTotalEnergyDeposit(step.GetTotalEnergyDeposit()); + fpHyperStep->SetNonIonizingEnergyDeposit(step.GetNonIonizingEnergyDeposit()); + fpHyperStep->SetControlFlag(step.GetControlFlag()); + + *(fpHyperStep->GetPreStepPoint()) = *(fpHyperStep->GetPostStepPoint()); + *(fpHyperStep->GetPostStepPoint()) = *(step.GetPostStepPoint()); + + fpHyperStep->GetPreStepPoint()->SetStepStatus(prevStatHyp); + } + + if(fOnBoundary) + { fpHyperStep->GetPostStepPoint()->SetStepStatus(fGeomBoundary); } +} + +void G4ParallelWorldProcess::SwitchMaterial(G4StepPoint* realWorldStepPoint) +{ + if(realWorldStepPoint->GetStepStatus()==fWorldBoundary) return; + G4VPhysicalVolume* thePhys = fNewGhostTouchable->GetVolume(); + if(thePhys) + { + G4Material* ghostMaterial = thePhys->GetLogicalVolume()->GetMaterial(); + if(ghostMaterial) + { + G4Region* ghostRegion = thePhys->GetLogicalVolume()->GetRegion(); + G4ProductionCuts* prodCuts = + realWorldStepPoint->GetMaterialCutsCouple()->GetProductionCuts(); + if(ghostRegion) + { + G4ProductionCuts* ghostProdCuts = ghostRegion->GetProductionCuts(); + if(ghostProdCuts) prodCuts = ghostProdCuts; + } + const G4MaterialCutsCouple* ghostMCCouple = + G4ProductionCutsTable::GetProductionCutsTable() + ->GetMaterialCutsCouple(ghostMaterial,prodCuts); + if(ghostMCCouple) + { + realWorldStepPoint->SetMaterial(ghostMaterial); + realWorldStepPoint->SetMaterialCutsCouple(ghostMCCouple); + *(fpHyperStep->GetPostStepPoint()) = *(fGhostPostStepPoint); + fpHyperStep->GetPostStepPoint()->SetMaterial(ghostMaterial); + fpHyperStep->GetPostStepPoint()->SetMaterialCutsCouple(ghostMCCouple); + } + else + { + G4cout << "!!! MaterialCutsCouple is not found for " + << ghostMaterial->GetName() << "." << G4endl + << " Material in real world (" + << realWorldStepPoint->GetMaterial()->GetName() + << ") is used." << G4endl; + } + } + } +} + +G4bool G4ParallelWorldProcess::IsAtRestRequired(G4ParticleDefinition* partDef) +{ + G4int pdgCode = partDef->GetPDGEncoding(); + if(pdgCode==0) + { + G4String partName = partDef->GetParticleName(); + if(partName=="opticalphoton") return false; + if(partName=="geantino") return false; + if(partName=="chargedgeantino") return false; + } + else + { + if(pdgCode==22) return false; // gamma + if(pdgCode==11) return false; // electron + if(pdgCode==2212) return false; // proton + if(pdgCode==-12) return false; // anti_nu_e + if(pdgCode==12) return false; // nu_e + if(pdgCode==-14) return false; // anti_nu_mu + if(pdgCode==14) return false; // nu_mu + if(pdgCode==-16) return false; // anti_nu_tau + if(pdgCode==16) return false; // nu_tau + } + return true; +} + diff --git a/src/G4.10.04.p02fixes/G4PhysicalVolumeModel.cc b/src/G4.10.04.p02fixes/G4PhysicalVolumeModel.cc new file mode 100644 index 0000000..e0ecdf7 --- /dev/null +++ b/src/G4.10.04.p02fixes/G4PhysicalVolumeModel.cc @@ -0,0 +1,1060 @@ +// +// ******************************************************************** +// * 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: G4PhysicalVolumeModel.cc 106122 2017-09-13 12:51:53Z gcosmo $ +// +// +// John Allison 31st December 1997. +// Model for physical volumes. + +#include "G4PhysicalVolumeModel.hh" + +#include "G4ModelingParameters.hh" +#include "G4VGraphicsScene.hh" +#include "G4VPhysicalVolume.hh" +#include "G4VPVParameterisation.hh" +#include "G4LogicalVolume.hh" +#include "G4VSolid.hh" +#include "G4SubtractionSolid.hh" +#include "G4IntersectionSolid.hh" +#include "G4Material.hh" +#include "G4VisAttributes.hh" +#include "G4BoundingSphereScene.hh" +#include "G4PhysicalVolumeSearchScene.hh" +#include "G4TransportationManager.hh" +#include "G4Polyhedron.hh" +#include "HepPolyhedronProcessor.h" +#include "G4AttDefStore.hh" +#include "G4AttDef.hh" +#include "G4AttValue.hh" +#include "G4UnitsTable.hh" +#include "G4Vector3D.hh" + +#include + +G4PhysicalVolumeModel::G4PhysicalVolumeModel +(G4VPhysicalVolume* pVPV + , G4int requestedDepth + , const G4Transform3D& modelTransformation + , const G4ModelingParameters* pMP + , G4bool useFullExtent) +: G4VModel (modelTransformation, pMP) +, fpTopPV (pVPV) +, fTopPVCopyNo (0) +, fRequestedDepth (requestedDepth) +, fUseFullExtent (useFullExtent) +, fCurrentDepth (0) +, fpCurrentPV (0) +, fpCurrentLV (0) +, fpCurrentMaterial (0) +, fpCurrentTransform (0) +, fAbort (false) +, fCurtailDescent (false) +, fpClippingSolid (0) +, fClippingMode (subtraction) +{ + fType = "G4PhysicalVolumeModel"; + + if (!fpTopPV) { + + // In some circumstances creating an "empty" G4PhysicalVolumeModel is + // allowed, so I have supressed the G4Exception below. If it proves to + // be a problem we might have to re-instate it, but it is unlikley to + // be used except by visualisation experts. See, for example, /vis/list, + // where it is used simply to get a list of G4AttDefs. + // G4Exception + // ("G4PhysicalVolumeModel::G4PhysicalVolumeModel", + // "modeling0010", FatalException, "Null G4PhysicalVolumeModel pointer."); + + fTopPVName = "NULL"; + fGlobalTag = "Empty"; + fGlobalDescription = "G4PhysicalVolumeModel " + fGlobalTag; + + } else { + + fTopPVName = fpTopPV -> GetName (); + fTopPVCopyNo = fpTopPV -> GetCopyNo (); + std::ostringstream o; + o << fpTopPV -> GetCopyNo (); + fGlobalTag = fpTopPV -> GetName () + "." + o.str(); + fGlobalDescription = "G4PhysicalVolumeModel " + fGlobalTag; + + fpCurrentPV = fpTopPV; + if (fpCurrentPV) fpCurrentLV = fpCurrentPV->GetLogicalVolume(); + if (fpCurrentLV) fpCurrentMaterial = fpCurrentLV->GetMaterial(); + fpCurrentTransform = const_cast(&modelTransformation); + + CalculateExtent (); + } +} + +G4PhysicalVolumeModel::~G4PhysicalVolumeModel () +{ + delete fpClippingSolid; +} + +void G4PhysicalVolumeModel::CalculateExtent () +{ + if (fUseFullExtent) { + fExtent = fpTopPV -> GetLogicalVolume () -> GetSolid () -> GetExtent (); + } + else { + G4BoundingSphereScene bsScene(this); + const G4int tempRequestedDepth = fRequestedDepth; + fRequestedDepth = -1; // Always search to all depths to define extent. + const G4ModelingParameters* tempMP = fpMP; + G4ModelingParameters mParams + (0, // No default vis attributes needed. + G4ModelingParameters::wf, // wireframe (not relevant for this). + true, // Global culling. + true, // Cull invisible volumes. + false, // Density culling. + 0., // Density (not relevant if density culling false). + true, // Cull daughters of opaque mothers. + 24); // No of sides (not relevant for this operation). + fpMP = &mParams; + DescribeYourselfTo (bsScene); + G4double radius = bsScene.GetRadius(); + if (radius < 0.) { // Nothing in the scene. + fExtent = fpTopPV -> GetLogicalVolume () -> GetSolid () -> GetExtent (); + } else { + // Transform back to coordinates relative to the top + // transformation, which is in G4VModel::fTransform. This makes + // it conform to all models, which are defined by a + // transformation and an extent relative to that + // transformation... + G4Point3D centre = bsScene.GetCentre(); + centre.transform(fTransform.inverse()); + fExtent = G4VisExtent(centre, radius); + } + fpMP = tempMP; + fRequestedDepth = tempRequestedDepth; + } +} + +void G4PhysicalVolumeModel::DescribeYourselfTo +(G4VGraphicsScene& sceneHandler) +{ + if (!fpTopPV) G4Exception + ("G4PhysicalVolumeModel::DescribeYourselfTo", + "modeling0012", FatalException, "No model."); + + if (!fpMP) G4Exception + ("G4PhysicalVolumeModel::DescribeYourselfTo", + "modeling0003", FatalException, "No modeling parameters."); + + // For safety... + fCurrentDepth = 0; + + G4Transform3D startingTransformation = fTransform; + + VisitGeometryAndGetVisReps + (fpTopPV, + fRequestedDepth, + startingTransformation, + sceneHandler); + + // Clear data... + fCurrentDepth = 0; + fpCurrentPV = 0; + fpCurrentLV = 0; + fpCurrentMaterial = 0; + if (fFullPVPath.size() != fBaseFullPVPath.size()) { + // They should be equal if pushing and popping is happening properly. + G4Exception + ("G4PhysicalVolumeModel::DescribeYourselfTo", + "modeling0013", + FatalException, + "Path at start of modeling not equal to base path. Something badly" + "\nwrong. Please contact visualisation coordinator."); + } + fDrawnPVPath.clear(); + fAbort = false; + fCurtailDescent = false; +} + +G4String G4PhysicalVolumeModel::GetCurrentTag () const +{ + if (fpCurrentPV) { + std::ostringstream o; + o << fpCurrentPV -> GetCopyNo (); + return fpCurrentPV -> GetName () + "." + o.str(); + } + else { + return "WARNING: NO CURRENT VOLUME - global tag is " + fGlobalTag; + } +} + +G4String G4PhysicalVolumeModel::GetCurrentDescription () const +{ + return "G4PhysicalVolumeModel " + GetCurrentTag (); +} + +void G4PhysicalVolumeModel::VisitGeometryAndGetVisReps +(G4VPhysicalVolume* pVPV, + G4int requestedDepth, + const G4Transform3D& theAT, + G4VGraphicsScene& sceneHandler) +{ + // Visits geometry structure to a given depth (requestedDepth), starting + // at given physical volume with given starting transformation and + // describes volumes to the scene handler. + // requestedDepth < 0 (default) implies full visit. + // theAT is the Accumulated Transformation. + + // Find corresponding logical volume and (later) solid, storing in + // local variables to preserve re-entrancy. + G4LogicalVolume* pLV = pVPV -> GetLogicalVolume (); + + G4VSolid* pSol; + G4Material* pMaterial; + + if (!(pVPV -> IsReplicated ())) { + // Non-replicated physical volume. + pSol = pLV -> GetSolid (); + pMaterial = pLV -> GetMaterial (); + DescribeAndDescend (pVPV, requestedDepth, pLV, pSol, pMaterial, + theAT, sceneHandler); + } + else { + // Replicated or parametrised physical volume. + EAxis axis; + G4int nReplicas; + G4double width; + G4double offset; + G4bool consuming; + pVPV -> GetReplicationData (axis, nReplicas, width, offset, consuming); + if (fCurrentDepth == 0) nReplicas = 1; // Just draw first + G4VPVParameterisation* pP = pVPV -> GetParameterisation (); + if (pP) { // Parametrised volume. + for (int n = 0; n < nReplicas; n++) { + pSol = pP -> ComputeSolid (n, pVPV); + pP -> ComputeTransformation (n, pVPV); + pSol -> ComputeDimensions (pP, n, pVPV); + pVPV -> SetCopyNo (n); + // Create a touchable of current parent for ComputeMaterial. + // fFullPVPath has not been updated yet so at this point it + // corresponds to the parent. + G4PhysicalVolumeModelTouchable parentTouchable(fFullPVPath); + pMaterial = pP -> ComputeMaterial (n, pVPV, &parentTouchable); + DescribeAndDescend (pVPV, requestedDepth, pLV, pSol, pMaterial, + theAT, sceneHandler); + } + } + else { // Plain replicated volume. From geometry_guide.txt... + // The replica's positions are claculated by means of a linear formula. + // Replication may occur along: + // + // o Cartesian axes (kXAxis,kYAxis,kZAxis) + // + // The replications, of specified width have coordinates of + // form (-width*(nReplicas-1)*0.5+n*width,0,0) where n=0.. nReplicas-1 + // for the case of kXAxis, and are unrotated. + // + // o Radial axis (cylindrical polar) (kRho) + // + // The replications are cons/tubs sections, centred on the origin + // and are unrotated. + // They have radii of width*n+offset to width*(n+1)+offset + // where n=0..nReplicas-1 + // + // o Phi axis (cylindrical polar) (kPhi) + // The replications are `phi sections' or wedges, and of cons/tubs form + // They have phi of offset+n*width to offset+(n+1)*width where + // n=0..nReplicas-1 + // + pSol = pLV -> GetSolid (); + pMaterial = pLV -> GetMaterial (); + G4ThreeVector originalTranslation = pVPV -> GetTranslation (); + G4RotationMatrix* pOriginalRotation = pVPV -> GetRotation (); + G4double originalRMin = 0., originalRMax = 0.; + if (axis == kRho && pSol->GetEntityType() == "G4Tubs") { + originalRMin = ((G4Tubs*)pSol)->GetInnerRadius(); + originalRMax = ((G4Tubs*)pSol)->GetOuterRadius(); + } + G4bool visualisable = true; + for (int n = 0; n < nReplicas; n++) { + G4ThreeVector translation; // Identity. + G4RotationMatrix rotation; // Identity - life enough for visualizing. + G4RotationMatrix* pRotation = 0; + switch (axis) { + default: + case kXAxis: + translation = G4ThreeVector (-width*(nReplicas-1)*0.5+n*width,0,0); + break; + case kYAxis: + translation = G4ThreeVector (0,-width*(nReplicas-1)*0.5+n*width,0); + break; + case kZAxis: + translation = G4ThreeVector (0,0,-width*(nReplicas-1)*0.5+n*width); + break; + case kRho: + if (pSol->GetEntityType() == "G4Tubs") { + ((G4Tubs*)pSol)->SetInnerRadius(width*n+offset); + ((G4Tubs*)pSol)->SetOuterRadius(width*(n+1)+offset); + } else { + if (fpMP->IsWarning()) + G4cout << + "G4PhysicalVolumeModel::VisitGeometryAndGetVisReps: WARNING:" + "\n built-in replicated volumes replicated in radius for " + << pSol->GetEntityType() << + "-type\n solids (your solid \"" + << pSol->GetName() << + "\") are not visualisable." + << G4endl; + visualisable = false; + } + break; + case kPhi: + rotation.rotateZ (-(offset+(n+0.5)*width)); + // Minus Sign because for the physical volume we need the + // coordinate system rotation. + pRotation = &rotation; + break; + } + pVPV -> SetTranslation (translation); + pVPV -> SetRotation (pRotation); + pVPV -> SetCopyNo (n); + if (visualisable) { + DescribeAndDescend (pVPV, requestedDepth, pLV, pSol, pMaterial, + theAT, sceneHandler); + } + } + // Restore originals... + pVPV -> SetTranslation (originalTranslation); + pVPV -> SetRotation (pOriginalRotation); + if (axis == kRho && pSol->GetEntityType() == "G4Tubs") { + ((G4Tubs*)pSol)->SetInnerRadius(originalRMin); + ((G4Tubs*)pSol)->SetOuterRadius(originalRMax); + } + } + } +} + +void G4PhysicalVolumeModel::DescribeAndDescend +(G4VPhysicalVolume* pVPV, + G4int requestedDepth, + G4LogicalVolume* pLV, + G4VSolid* pSol, + G4Material* pMaterial, + const G4Transform3D& theAT, + G4VGraphicsScene& sceneHandler) +{ + // Maintain useful data members... + fpCurrentPV = pVPV; + fpCurrentLV = pLV; + fpCurrentMaterial = pMaterial; + + const G4RotationMatrix objectRotation = pVPV -> GetObjectRotationValue (); + const G4ThreeVector& translation = pVPV -> GetTranslation (); + G4Transform3D theLT (G4Transform3D (objectRotation, translation)); + + // Compute the accumulated transformation... + // Note that top volume's transformation relative to the world + // coordinate system is specified in theAT == startingTransformation + // = fTransform (see DescribeYourselfTo), so first time through the + // volume's own transformation, which is only relative to its + // mother, i.e., not relative to the world coordinate system, should + // not be accumulated. + G4Transform3D theNewAT (theAT); + if (fCurrentDepth != 0) theNewAT = theAT * theLT; + fpCurrentTransform = &theNewAT; + + const G4VisAttributes* pVisAttribs = pLV->GetVisAttributes(); + if (!pVisAttribs) pVisAttribs = fpMP->GetDefaultVisAttributes(); + // Beware - pVisAttribs might still be zero - probably will, since that's + // the default for G4ModelingParameters. So create one if necessary... + if (!pVisAttribs) { + static G4VisAttributes defaultVisAttribs; + pVisAttribs = &defaultVisAttribs; + } + // From here, can assume pVisAttribs is a valid pointer. This is necessary + // because PreAddSolid needs a vis attributes object. + + // Make decision to draw... + G4bool thisToBeDrawn = true; + + // Update full path of physical volumes... + G4int copyNo = fpCurrentPV->GetCopyNo(); + fFullPVPath.push_back + (G4PhysicalVolumeNodeID + (fpCurrentPV,copyNo,fCurrentDepth,*fpCurrentTransform)); + + // Check if vis attributes are to be modified by a /vis/touchable/set/ command. + const auto& vams = fpMP->GetVisAttributesModifiers(); + if (vams.size()) { + // OK, we have some VAMs (Vis Attributes Modifiers). + for (const auto& vam: vams) { + const auto& vamPath = vam.GetPVNameCopyNoPath(); + if (vamPath.size() == fFullPVPath.size()) { + // OK, we have a size match. + // Check the volume name/copy number path. + auto iVAMNameCopyNo = vamPath.begin(); + auto iPVNodeId = fFullPVPath.begin(); + for (; iVAMNameCopyNo != vamPath.end(); ++iVAMNameCopyNo, ++iPVNodeId) { + if (!( + iVAMNameCopyNo->GetName() == + iPVNodeId->GetPhysicalVolume()->GetName() && + iVAMNameCopyNo->GetCopyNo() == + iPVNodeId->GetPhysicalVolume()->GetCopyNo() + )) { + // This path element does NOT match. + break; + } + } + if (iVAMNameCopyNo == vamPath.end()) { + // OK, the paths match (the above loop terminated normally). + // Create a vis atts object for the modified vis atts. + // It is static so that we may return a reliable pointer to it. + static G4VisAttributes modifiedVisAtts; + // Initialise it with the current vis atts and reset the pointer. + modifiedVisAtts = *pVisAttribs; + pVisAttribs = &modifiedVisAtts; + const G4VisAttributes& transVisAtts = vam.GetVisAttributes(); + switch (vam.GetVisAttributesSignifier()) { + case G4ModelingParameters::VASVisibility: + modifiedVisAtts.SetVisibility(transVisAtts.IsVisible()); + break; + case G4ModelingParameters::VASDaughtersInvisible: + modifiedVisAtts.SetDaughtersInvisible + (transVisAtts.IsDaughtersInvisible()); + break; + case G4ModelingParameters::VASColour: + modifiedVisAtts.SetColour(transVisAtts.GetColour()); + break; + case G4ModelingParameters::VASLineStyle: + modifiedVisAtts.SetLineStyle(transVisAtts.GetLineStyle()); + break; + case G4ModelingParameters::VASLineWidth: + modifiedVisAtts.SetLineWidth(transVisAtts.GetLineWidth()); + break; + case G4ModelingParameters::VASForceWireframe: + if (transVisAtts.IsForceDrawingStyle()) { + if (transVisAtts.GetForcedDrawingStyle() == + G4VisAttributes::wireframe) { + modifiedVisAtts.SetForceWireframe(true); + } + } + break; + case G4ModelingParameters::VASForceSolid: + if (transVisAtts.IsForceDrawingStyle()) { + if (transVisAtts.GetForcedDrawingStyle() == + G4VisAttributes::solid) { + modifiedVisAtts.SetForceSolid(true); + } + } + break; + case G4ModelingParameters::VASForceAuxEdgeVisible: + if (transVisAtts.IsForceAuxEdgeVisible()) { + modifiedVisAtts.SetForceAuxEdgeVisible + (transVisAtts.IsForcedAuxEdgeVisible()); + } + break; + case G4ModelingParameters::VASForceLineSegmentsPerCircle: + modifiedVisAtts.SetForceLineSegmentsPerCircle + (transVisAtts.GetForcedLineSegmentsPerCircle()); + break; + } + } + } + } + } + + // There are various reasons why this volume + // might not be drawn... + G4bool culling = fpMP->IsCulling(); + G4bool cullingInvisible = fpMP->IsCullingInvisible(); + G4bool markedVisible = pVisAttribs->IsVisible(); + G4bool cullingLowDensity = fpMP->IsDensityCulling(); + G4double density = pMaterial? pMaterial->GetDensity(): 0; + G4double densityCut = fpMP -> GetVisibleDensity (); + + // 1) Global culling is on.... + if (culling) { + // 2) Culling of invisible volumes is on... + if (cullingInvisible) { + // 3) ...and the volume is marked not visible... + if (!markedVisible) thisToBeDrawn = false; + } + // 4) Or culling of low density volumes is on... + if (cullingLowDensity) { + // 5) ...and density is less than cut value... + if (density < densityCut) thisToBeDrawn = false; + } + } + // 6) The user has asked for all further traversing to be aborted... + if (fAbort) thisToBeDrawn = false; + +#ifdef BYPASS_DRAWING_CLIPPED_VOLUMES + + // Check if a view clipping operation cuts this volume from the scene + + bool thisToBeBypassed = false; + G4VSolid* pIntersector = fpMP->GetSectionSolid(); + G4VSolid* pSubtractor = fpMP->GetCutawaySolid(); + if (fpClippingSolid) { + switch (fClippingMode) { + case subtraction: + pSubtractor = fpClippingSolid; + break; + case intersection: + pIntersector = fpClippingSolid; + break; + } + } + + G4DisplacedSolid *pClipper; + if ((pClipper = dynamic_cast(pIntersector))) + { + G4AffineTransform clipAT(pClipper->GetTransform()); + G4AffineTransform currAT(fpCurrentTransform->getRotation().inverse(), + fpCurrentTransform->getTranslation()); + G4AffineTransform combAT; + combAT.Product(currAT,clipAT); + G4DisplacedSolid pClipped("temporary_to_clip",pSol,combAT); + G4VisExtent clipper(pClipper->GetConstituentMovedSolid()->GetExtent()); + G4VisExtent clipped(pClipped.GetExtent()); + thisToBeBypassed = (clipper.GetXmax() < clipped.GetXmin()) + || (clipper.GetXmin() > clipped.GetXmax()) + || (clipper.GetYmax() < clipped.GetYmin()) + || (clipper.GetYmin() > clipped.GetYmax()) + || (clipper.GetZmax() < clipped.GetZmin()) + || (clipper.GetZmin() > clipped.GetZmax()); + } + + if ((pClipper = dynamic_cast(pSubtractor))) + { + G4AffineTransform clipAT(pClipper->GetTransform()); + G4AffineTransform currAT(fpCurrentTransform->getRotation().inverse(), + fpCurrentTransform->getTranslation()); + G4AffineTransform combAT; + combAT.Product(currAT,clipAT); + G4DisplacedSolid pClipped("temporary_to_clip",pSol,combAT); + G4VisExtent clipper(pClipper->GetConstituentMovedSolid()->GetExtent()); + G4VisExtent clipped(pClipped.GetExtent()); + thisToBeBypassed = (clipper.GetXmax() > clipped.GetXmax()) + && (clipper.GetXmin() < clipped.GetXmin()) + && (clipper.GetYmax() > clipped.GetYmax()) + && (clipper.GetYmin() < clipped.GetYmin()) + && (clipper.GetZmax() > clipped.GetZmax()) + && (clipper.GetZmin() < clipped.GetZmin()); + } + + thisToBeDrawn = thisToBeDrawn && (! thisToBeBypassed); + +#endif + + // Record thisToBeDrawn in path... + fFullPVPath.back().SetDrawn(thisToBeDrawn); + + if (thisToBeDrawn) { + + // Update path of drawn physical volumes... + fDrawnPVPath.push_back + (G4PhysicalVolumeNodeID + (fpCurrentPV,copyNo,fCurrentDepth,*fpCurrentTransform,thisToBeDrawn)); + + if (fpMP->IsExplode() && fDrawnPVPath.size() == 1) { + // For top-level drawn volumes, explode along radius... + G4Transform3D centering = G4Translate3D(fpMP->GetExplodeCentre()); + G4Transform3D centred = centering.inverse() * theNewAT; + G4Scale3D oldScale; + G4Rotate3D oldRotation; + G4Translate3D oldTranslation; + centred.getDecomposition(oldScale, oldRotation, oldTranslation); + G4double explodeFactor = fpMP->GetExplodeFactor(); + G4Translate3D newTranslation = + G4Translate3D(explodeFactor * oldTranslation.dx(), + explodeFactor * oldTranslation.dy(), + explodeFactor * oldTranslation.dz()); + theNewAT = centering * newTranslation * oldRotation * oldScale; + } + + DescribeSolid (theNewAT, pSol, pVisAttribs, sceneHandler); + + } + + // Make decision to draw daughters, if any. There are various + // reasons why daughters might not be drawn... + + // First, reasons that do not depend on culling policy... + G4int nDaughters = pLV->GetNoDaughters(); +#ifdef BYPASS_DRAWING_CLIPPED_VOLUMES + G4bool daughtersToBeDrawn = ! thisToBeBypassed; +#else + G4bool daughtersToBeDrawn = true; +#endif + // 1) There are no daughters... + if (!nDaughters) daughtersToBeDrawn = false; + // 2) We are at the limit if requested depth... + else if (requestedDepth == 0) daughtersToBeDrawn = false; + // 3) The user has asked for all further traversing to be aborted... + else if (fAbort) daughtersToBeDrawn = false; + // 4) The user has asked that the descent be curtailed... + else if (fCurtailDescent) daughtersToBeDrawn = false; + + // Now, reasons that depend on culling policy... + else { + G4bool daughtersInvisible = pVisAttribs->IsDaughtersInvisible(); + // Culling of covered daughters request. This is computed in + // G4VSceneHandler::CreateModelingParameters() depending on view + // parameters... + G4bool cullingCovered = fpMP->IsCullingCovered(); + G4bool surfaceDrawing = + fpMP->GetDrawingStyle() == G4ModelingParameters::hsr || + fpMP->GetDrawingStyle() == G4ModelingParameters::hlhsr; + if (pVisAttribs->IsForceDrawingStyle()) { + switch (pVisAttribs->GetForcedDrawingStyle()) { + default: + case G4VisAttributes::wireframe: surfaceDrawing = false; break; + case G4VisAttributes::solid: surfaceDrawing = true; break; + } + } + G4bool opaque = pVisAttribs->GetColour().GetAlpha() >= 1.; + // 5) Global culling is on.... + if (culling) { + // 6) ..and culling of invisible volumes is on... + if (cullingInvisible) { + // 7) ...and the mother requests daughters invisible + if (daughtersInvisible) daughtersToBeDrawn = false; + } + // 8) Or culling of covered daughters is requested... + if (cullingCovered) { + // 9) ...and surface drawing is operating... + if (surfaceDrawing) { + // 10) ...but only if mother is visible... + if (thisToBeDrawn) { + // 11) ...and opaque... + if (opaque) daughtersToBeDrawn = false; + } + } + } + } + } + + if (daughtersToBeDrawn) { + for (G4int iDaughter = 0; iDaughter < nDaughters; iDaughter++) { + // Store daughter pVPV in local variable ready for recursion... + G4VPhysicalVolume* pDaughterVPV = pLV -> GetDaughter (iDaughter); + // Descend the geometry structure recursively... + fCurrentDepth++; + VisitGeometryAndGetVisReps + (pDaughterVPV, requestedDepth - 1, theNewAT, sceneHandler); + fCurrentDepth--; + } + } + + // Reset for normal descending of next volume at this level... + fCurtailDescent = false; + + // Pop item from paths physical volumes... + fFullPVPath.pop_back(); + if (thisToBeDrawn) { + fDrawnPVPath.pop_back(); + } +} + +void G4PhysicalVolumeModel::DescribeSolid +(const G4Transform3D& theAT, + G4VSolid* pSol, + const G4VisAttributes* pVisAttribs, + G4VGraphicsScene& sceneHandler) +{ + sceneHandler.PreAddSolid (theAT, *pVisAttribs); + + G4VSolid* pSectionSolid = fpMP->GetSectionSolid(); + G4VSolid* pCutawaySolid = fpMP->GetCutawaySolid(); + + if (!fpClippingSolid && !pSectionSolid && !pCutawaySolid) { + + pSol -> DescribeYourselfTo (sceneHandler); // Standard treatment. + + } else { + + // Clipping, etc., performed by Boolean operations. + + // First, get polyhedron for current solid... + if (pVisAttribs->IsForceLineSegmentsPerCircle()) + G4Polyhedron::SetNumberOfRotationSteps + (pVisAttribs->GetForcedLineSegmentsPerCircle()); + else + G4Polyhedron::SetNumberOfRotationSteps(fpMP->GetNoOfSides()); + const G4Polyhedron* pOriginal = pSol->GetPolyhedron(); + //G4Polyhedron::ResetNumberOfRotationSteps(); + + if (!pOriginal) { + + if (fpMP->IsWarning()) + G4cout << + "WARNING: G4PhysicalVolumeModel::DescribeSolid: solid\n \"" + << pSol->GetName() << + "\" has no polyhedron. Cannot by clipped." + << G4endl; + pSol -> DescribeYourselfTo (sceneHandler); // Standard treatment. + + } else { + + G4Polyhedron resultant(*pOriginal); + G4VisAttributes resultantVisAttribs(*pVisAttribs); + G4VSolid* resultantSolid = 0; + + if (fpClippingSolid) { + switch (fClippingMode) { + default: + case subtraction: + resultantSolid = new G4SubtractionSolid + ("resultant_solid", pSol, fpClippingSolid, theAT.inverse()); + break; + case intersection: + resultantSolid = new G4IntersectionSolid + ("resultant_solid", pSol, fpClippingSolid, theAT.inverse()); + break; + } + } + + if (pSectionSolid) { + resultantSolid = new G4IntersectionSolid + ("sectioned_solid", pSol, pSectionSolid, theAT.inverse()); + } + + if (pCutawaySolid) { + resultantSolid = new G4SubtractionSolid + ("cutaway_solid", pSol, pCutawaySolid, theAT.inverse()); + } + + G4Polyhedron* tmpResultant = resultantSolid->GetPolyhedron(); + if (tmpResultant) resultant = *tmpResultant; + else { + if (fpMP->IsWarning()) + G4cout << + "WARNING: G4PhysicalVolumeModel::DescribeSolid: resultant polyhedron for" + "\n solid \"" << pSol->GetName() << + "\" not defined due to error during Boolean processing." + "\n Original will be drawn in red." + << G4endl; + resultantVisAttribs.SetColour(G4Colour::Red()); + } + + delete resultantSolid; + + // Finally, force polyhedron drawing... + resultant.SetVisAttributes(resultantVisAttribs); + sceneHandler.BeginPrimitives(theAT); + sceneHandler.AddPrimitive(resultant); + sceneHandler.EndPrimitives(); + } + } + sceneHandler.PostAddSolid (); +} + +G4bool G4PhysicalVolumeModel::Validate (G4bool warn) +{ + G4TransportationManager* transportationManager = + G4TransportationManager::GetTransportationManager (); + + size_t nWorlds = transportationManager->GetNoWorlds(); + + G4bool found = false; + + std::vector::iterator iterWorld = + transportationManager->GetWorldsIterator(); + for (size_t i = 0; i < nWorlds; ++i, ++iterWorld) { + G4VPhysicalVolume* world = (*iterWorld); + if (!world) break; // This can happen if geometry has been cleared/destroyed. + // The idea now is to seek a PV with the same name and copy no + // in the hope it's the same one!! + G4PhysicalVolumeModel searchModel (world); + G4int verbosity = 0; // Suppress messages from G4PhysicalVolumeSearchScene. + G4PhysicalVolumeSearchScene searchScene + (&searchModel, fTopPVName, fTopPVCopyNo, verbosity); + G4ModelingParameters mp; // Default modeling parameters for this search. + mp.SetDefaultVisAttributes(fpMP? fpMP->GetDefaultVisAttributes(): 0); + searchModel.SetModelingParameters (&mp); + searchModel.DescribeYourselfTo (searchScene); + G4VPhysicalVolume* foundVolume = searchScene.GetFoundVolume (); + if (foundVolume) { + if (foundVolume != fpTopPV && warn) { + G4cout << + "G4PhysicalVolumeModel::Validate(): A volume of the same name and" + "\n copy number (\"" + << fTopPVName << "\", copy " << fTopPVCopyNo + << ") still exists and is being used." + "\n But it is not the same volume you originally specified" + "\n in /vis/scene/add/." + << G4endl; + } + fpTopPV = foundVolume; + CalculateExtent (); + found = true; + } + } + if (found) return true; + else { + if (warn) { + G4cout << + "G4PhysicalVolumeModel::Validate(): No volume of name and" + "\n copy number (\"" + << fTopPVName << "\", copy " << fTopPVCopyNo + << ") exists." + << G4endl; + } + return false; + } +} + +const std::map* G4PhysicalVolumeModel::GetAttDefs() const +{ + G4bool isNew; + std::map* store + = G4AttDefStore::GetInstance("G4PhysicalVolumeModel", isNew); + if (isNew) { + (*store)["PVPath"] = + G4AttDef("PVPath","Physical Volume Path","Physics","","G4String"); + (*store)["LVol"] = + G4AttDef("LVol","Logical Volume","Physics","","G4String"); + (*store)["Solid"] = + G4AttDef("Solid","Solid Name","Physics","","G4String"); + (*store)["EType"] = + G4AttDef("EType","Entity Type","Physics","","G4String"); + (*store)["DmpSol"] = + G4AttDef("DmpSol","Dump of Solid properties","Physics","","G4String"); + (*store)["LocalTrans"] = + G4AttDef("LocalTrans","Local transformation of volume","Physics","","G4String"); + (*store)["GlobalTrans"] = + G4AttDef("GlobalTrans","Global transformation of volume","Physics","","G4String"); + (*store)["Material"] = + G4AttDef("Material","Material Name","Physics","","G4String"); + (*store)["Density"] = + G4AttDef("Density","Material Density","Physics","G4BestUnit","G4double"); + (*store)["State"] = + G4AttDef("State","Material State (enum undefined,solid,liquid,gas)","Physics","","G4String"); + (*store)["Radlen"] = + G4AttDef("Radlen","Material Radiation Length","Physics","G4BestUnit","G4double"); + (*store)["Region"] = + G4AttDef("Region","Cuts Region","Physics","","G4String"); + (*store)["RootRegion"] = + G4AttDef("RootRegion","Root Region (0/1 = false/true)","Physics","","G4bool"); + } + return store; +} + +#include + +static std::ostream& operator<< (std::ostream& o, const G4Transform3D t) +{ + using namespace std; + + G4Scale3D sc; + G4Rotate3D r; + G4Translate3D tl; + t.getDecomposition(sc, r, tl); + + const int w = 10; + + // Transformation itself + o << setw(w) << t.xx() << setw(w) << t.xy() << setw(w) << t.xz() << setw(w) << t.dx() << endl; + o << setw(w) << t.yx() << setw(w) << t.yy() << setw(w) << t.yz() << setw(w) << t.dy() << endl; + o << setw(w) << t.zx() << setw(w) << t.zy() << setw(w) << t.zz() << setw(w) << t.dz() << endl; + + // Translation + o << "= translation:" << endl; + o << setw(w) << tl.dx() << setw(w) << tl.dy() << setw(w) << tl.dz() << endl; + + // Rotation + o << "* rotation:" << endl; + o << setw(w) << r.xx() << setw(w) << r.xy() << setw(w) << r.xz() << endl; + o << setw(w) << r.yx() << setw(w) << r.yy() << setw(w) << r.yz() << endl; + o << setw(w) << r.zx() << setw(w) << r.zy() << setw(w) << r.zz() << endl; + + // Scale + o << "* scale:" << endl; + o << setw(w) << sc.xx() << setw(w) << sc.yy() << setw(w) << sc.zz() << endl; + + // Transformed axes + o << "Transformed axes:" << endl; + o << "x': " << r * G4Vector3D(1., 0., 0.) << endl; + o << "y': " << r * G4Vector3D(0., 1., 0.) << endl; + o << "z': " << r * G4Vector3D(0., 0., 1.) << endl; + + return o; +} + +std::vector* G4PhysicalVolumeModel::CreateCurrentAttValues() const +{ + std::vector* values = new std::vector; + std::ostringstream oss; + for (size_t i = 0; i < fFullPVPath.size(); ++i) { + oss << fFullPVPath[i].GetPhysicalVolume()->GetName() + << ':' << fFullPVPath[i].GetCopyNo(); + if (i != fFullPVPath.size() - 1) oss << '/'; + } + + if (!fpCurrentLV) { + G4Exception + ("G4PhysicalVolumeModel::CreateCurrentAttValues", + "modeling0004", + JustWarning, + "Current logical volume not defined."); + return values; + } + + values->push_back(G4AttValue("PVPath", oss.str(),"")); + values->push_back(G4AttValue("LVol", fpCurrentLV->GetName(),"")); + G4VSolid* pSol = fpCurrentLV->GetSolid(); + values->push_back(G4AttValue("Solid", pSol->GetName(),"")); + values->push_back(G4AttValue("EType", pSol->GetEntityType(),"")); + oss.str(""); oss << '\n' << *pSol; + values->push_back(G4AttValue("DmpSol", oss.str(),"")); + const G4RotationMatrix localRotation = fpCurrentPV->GetObjectRotationValue(); + const G4ThreeVector& localTranslation = fpCurrentPV->GetTranslation(); + oss.str(""); oss << '\n' << G4Transform3D(localRotation,localTranslation); + values->push_back(G4AttValue("LocalTrans", oss.str(),"")); + oss.str(""); oss << '\n' << *fpCurrentTransform; + values->push_back(G4AttValue("GlobalTrans", oss.str(),"")); + G4String matName = fpCurrentMaterial? fpCurrentMaterial->GetName(): G4String("No material"); + values->push_back(G4AttValue("Material", matName,"")); + G4double matDensity = fpCurrentMaterial? fpCurrentMaterial->GetDensity(): 0.; + values->push_back(G4AttValue("Density", G4BestUnit(matDensity,"Volumic Mass"),"")); + G4State matState = fpCurrentMaterial? fpCurrentMaterial->GetState(): kStateUndefined; + oss.str(""); oss << matState; + values->push_back(G4AttValue("State", oss.str(),"")); + G4double matRadlen = fpCurrentMaterial? fpCurrentMaterial->GetRadlen(): 0.; + values->push_back(G4AttValue("Radlen", G4BestUnit(matRadlen,"Length"),"")); + G4Region* region = fpCurrentLV->GetRegion(); + G4String regionName = region? region->GetName(): G4String("No region"); + values->push_back(G4AttValue("Region", regionName,"")); + oss.str(""); oss << fpCurrentLV->IsRootRegion(); + values->push_back(G4AttValue("RootRegion", oss.str(),"")); + return values; +} + +G4bool G4PhysicalVolumeModel::G4PhysicalVolumeNodeID::operator< + (const G4PhysicalVolumeModel::G4PhysicalVolumeNodeID& right) const +{ + if (fpPV < right.fpPV) return true; + if (fpPV == right.fpPV) { + if (fCopyNo < right.fCopyNo) return true; + if (fCopyNo == right.fCopyNo) + return fNonCulledDepth < right.fNonCulledDepth; + } + return false; +} + +std::ostream& operator<< + (std::ostream& os, const G4PhysicalVolumeModel::G4PhysicalVolumeNodeID& node) +{ + G4VPhysicalVolume* pPV = node.GetPhysicalVolume(); + if (pPV) { + os << pPV->GetName() + << ' ' << node.GetCopyNo() +// << '[' << node.GetNonCulledDepth() << ']' +// << ':' << node.GetTransform() + ; +// os << " ("; +// if (!node.GetDrawn()) os << "not "; +// os << "drawn)"; + } else { + os << " (Null node)"; + } + return os; +} + +std::ostream& operator<< +(std::ostream& os, const std::vector& path) +{ + for (const auto& nodeID: path) { + os << nodeID << ' '; + } + return os; +} + +G4PhysicalVolumeModel::G4PhysicalVolumeModelTouchable::G4PhysicalVolumeModelTouchable +(const std::vector& fullPVPath): + fFullPVPath(fullPVPath) {} + +const G4ThreeVector& G4PhysicalVolumeModel::G4PhysicalVolumeModelTouchable::GetTranslation(G4int depth) const +{ + size_t i = fFullPVPath.size() - depth - 1; + if (i >= fFullPVPath.size()) { + G4Exception("G4PhysicalVolumeModelTouchable::GetTranslation", + "modeling0005", + FatalErrorInArgument, + "Index out of range. Asking for non-existent depth"); + } + static G4ThreeVector tempTranslation; + tempTranslation = fFullPVPath[i].GetTransform().getTranslation(); + return tempTranslation; +} + +const G4RotationMatrix* G4PhysicalVolumeModel::G4PhysicalVolumeModelTouchable::GetRotation(G4int depth) const +{ + size_t i = fFullPVPath.size() - depth - 1; + if (i >= fFullPVPath.size()) { + G4Exception("G4PhysicalVolumeModelTouchable::GetRotation", + "modeling0006", + FatalErrorInArgument, + "Index out of range. Asking for non-existent depth"); + } + static G4RotationMatrix tempRotation; + tempRotation = fFullPVPath[i].GetTransform().getRotation(); + return &tempRotation; +} + +G4VPhysicalVolume* G4PhysicalVolumeModel::G4PhysicalVolumeModelTouchable::GetVolume(G4int depth) const +{ + size_t i = fFullPVPath.size() - depth - 1; + if (i >= fFullPVPath.size()) { + G4Exception("G4PhysicalVolumeModelTouchable::GetVolume", + "modeling0007", + FatalErrorInArgument, + "Index out of range. Asking for non-existent depth"); + } + return fFullPVPath[i].GetPhysicalVolume(); +} + +G4VSolid* G4PhysicalVolumeModel::G4PhysicalVolumeModelTouchable::GetSolid(G4int depth) const +{ + size_t i = fFullPVPath.size() - depth - 1; + if (i >= fFullPVPath.size()) { + G4Exception("G4PhysicalVolumeModelTouchable::GetSolid", + "modeling0008", + FatalErrorInArgument, + "Index out of range. Asking for non-existent depth"); + } + return fFullPVPath[i].GetPhysicalVolume()->GetLogicalVolume()->GetSolid(); +} + +G4int G4PhysicalVolumeModel::G4PhysicalVolumeModelTouchable::GetReplicaNumber(G4int depth) const +{ + size_t i = fFullPVPath.size() - depth - 1; + if (i >= fFullPVPath.size()) { + G4Exception("G4PhysicalVolumeModelTouchable::GetReplicaNumber", + "modeling0009", + FatalErrorInArgument, + "Index out of range. Asking for non-existent depth"); + } + return fFullPVPath[i].GetCopyNo(); +} diff --git a/src/G4.10.04.p02fixes/G4SteppingVerbose.cc b/src/G4.10.04.p02fixes/G4SteppingVerbose.cc new file mode 100644 index 0000000..94751d8 --- /dev/null +++ b/src/G4.10.04.p02fixes/G4SteppingVerbose.cc @@ -0,0 +1,883 @@ +// +// ******************************************************************** +// * 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: G4SteppingVerbose.cc 66241 2012-12-13 18:34:42Z gunter $ +// +//--------------------------------------------------------------- +// +// G4SteppingVerbose.cc +// +// Description: +// Implementation of the G4SteppingVerbose class +// Contact: +// Questions and comments to this code should be sent to +// Katsuya Amako (e-mail: Katsuya.Amako@kek.jp) +// Takashi Sasaki (e-mail: Takashi.Sasaki@kek.jp) +// +//--------------------------------------------------------------- + +#include "G4SteppingVerbose.hh" +#include "G4SteppingManager.hh" +#include "G4ForceCondition.hh" +#include "G4SystemOfUnits.hh" +#include "G4VSensitiveDetector.hh" // Include from 'hits/digi' +#include "G4StepStatus.hh" // Include from 'tracking' + +///#define G4_USE_G4BESTUNIT_FOR_VERBOSE 1 + +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE +#include "G4UnitsTable.hh" +#else +#define G4BestUnit(a,b) a +#endif + +////////////////////////////////////////////////// +G4SteppingVerbose::G4SteppingVerbose() +////////////////////////////////////////////////// +{ +#ifdef G4_TRACKING_DEBUG + G4cout << "G4SteppingVerbose has instantiated" << G4endl; +#endif +} + +////////////////////////////////////////////////// +G4SteppingVerbose::~G4SteppingVerbose() +////////////////////////////////////////////////// +{ +} + +////////////////////////////////////////////////// +void G4SteppingVerbose::NewStep() +////////////////////////////////////////////////// +{ +} + +////////////////////////////////////////////////// +void G4SteppingVerbose::AtRestDoItInvoked() +////////////////////////////////////////////////// + { + if(Silent==1){ return; } + + G4VProcess* ptProcManager; + CopyState(); + + if(verboseLevel >= 3 ){ + G4int npt=0; + G4cout << " **List of AtRestDoIt invoked:" << G4endl; + for(size_t np=0; np < MAXofAtRestLoops; np++){ + size_t npGPIL = MAXofAtRestLoops-np-1; + if( (*fSelectedAtRestDoItVector)[npGPIL] > 0 ){ + npt++; + ptProcManager = (*fAtRestDoItVector)[np]; + int cond = (*fSelectedPostStepDoItVector)[npGPIL]; + G4cout << " # " << npt << " : " + << ptProcManager->GetProcessName() + << ptProcManager->GetProcessName() + << ((cond == Forced)? " (Forced)" : + (cond == NotForced)? " (NotForced)" : + (cond == Conditionally)? " (Conditionally)" : + (cond == ExclusivelyForced)? " (ExclusivelyForced)" : + (cond == StronglyForced)? " (StronglyForced)" : "") + << G4endl; + } + } + + G4cout << " Generated secondries # : " << fN2ndariesAtRestDoIt << G4endl; + + if( fN2ndariesAtRestDoIt > 0 ){ + G4cout << " -- List of secondaries generated : " << "(x,y,z,kE,t,PID) --" << G4endl; + for( size_t lp1=(*fSecondary).size()-fN2ndariesAtRestDoIt; + lp1<(*fSecondary).size(); lp1++) { + G4cout << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy(),"Energy") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetGlobalTime(),"Time") << " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + } + } + + if( verboseLevel >= 4 ){ + ShowStep(); + G4cout << G4endl; + } +} +///////////////////////////////////////////////////// +void G4SteppingVerbose::AlongStepDoItAllDone() +///////////////////////////////////////////////////// +{ + if(Silent==1){ return; } + + G4VProcess* ptProcManager; + + CopyState(); + + if(verboseLevel >= 3){ + G4cout << G4endl; + G4cout << " >>AlongStepDoIt (after all invocations):" << G4endl; + G4cout << " ++List of invoked processes " << G4endl; + + for(size_t ci=0; ciGetProcessName() << G4endl; + } + } + + ShowStep(); + G4cout << G4endl; + G4cout << " ++List of secondaries generated " + << "(x,y,z,kE,t,PID):" + << " No. of secodaries = " + << (*fSecondary).size() << G4endl; + + if((*fSecondary).size()>0){ + for(size_t lp1=0; lp1<(*fSecondary).size(); lp1++){ + G4cout << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z(),"Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy(),"Energy") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetGlobalTime(),"Time") << " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + } + } +} +//////////////////////////////////////////////////// +void G4SteppingVerbose::PostStepDoItAllDone() +//////////////////////////////////////////////////// +{ + if(Silent==1){ return; } + + G4VProcess* ptProcManager; + + CopyState(); + + if( (fStepStatus == fPostStepDoItProc) | + (fCondition == Forced) | + (fCondition == Conditionally) | + (fCondition == ExclusivelyForced) | + (fCondition == StronglyForced) ){ + + if(verboseLevel >= 3){ + G4int npt=0; + G4cout << G4endl; + G4cout << " **PostStepDoIt (after all invocations):" << G4endl; + G4cout << " ++List of invoked processes " << G4endl; + + for(size_t np=0; np < MAXofPostStepLoops; np++){ + size_t npGPIL = MAXofPostStepLoops-np-1; + // This PostStepDoIt is really forced to invoke, anyway. + if( (*fSelectedPostStepDoItVector)[npGPIL] > 0){ + npt++; + ptProcManager = (*fPostStepDoItVector)[np]; + int cond = (*fSelectedPostStepDoItVector)[npGPIL]; + G4cout << " " << npt << ") " + << ptProcManager->GetProcessName() + << ((cond == Forced)? " (Forced)" : + (cond == NotForced)? " (NotForced)" : + (cond == Conditionally)? " (Conditionally)" : + (cond == ExclusivelyForced)? " (ExclusivelyForced)" : + (cond == StronglyForced)? " (StronglyForced)" : "") + << G4endl; + } + } + + ShowStep(); + G4cout << G4endl; + G4cout << " ++List of secondaries generated " + << "(x,y,z,kE,t,PID):" + << " No. of secodaries = " + << (*fSecondary).size() << G4endl; + G4cout << " [Note]Secondaries from AlongStepDoIt included." << G4endl; + + if((*fSecondary).size()>0){ + for(size_t lp1=0; lp1<(*fSecondary).size(); lp1++){ + G4cout << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x() , "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y() , "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z() , "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy() , "Energy") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetGlobalTime() , "Time") << " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + } + } + } +} + +///////////////////////////////////////// +void G4SteppingVerbose::StepInfo() +///////////////////////////////////////// +{ + if(Silent==1){ return; } + if(SilentStepInfo==1){ return; } + + CopyState(); + G4cout.precision(16); + G4int prec = G4cout.precision(3); + + if( verboseLevel >= 1 ){ + if( verboseLevel >= 4 ) VerboseTrack(); + if( verboseLevel >= 3 ){ + G4cout << G4endl; +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << std::setw( 5) << "#Step#" << " " + << std::setw( 8) << "X" << " " << std::setw( 8) << "Y" << " " + << std::setw( 8) << "Z" << " " + << std::setw( 9) << "KineE" << " " << std::setw( 8) << "dE" << " " + << std::setw(12) << "StepLeng" << " " << std::setw(12) << "TrackLeng" << " " + << std::setw(12) << "NextVolume" << " " << std::setw( 8) << "ProcName" << G4endl; +#else + G4cout << std::setw( 5) << "#Step#" << " " + << std::setw( 8) << "X(mm)" << " " << std::setw( 8) << "Y(mm)" << " " + << std::setw( 8) << "Z(mm)" << " " + << std::setw( 9) << "KinE(MeV)" << " " << std::setw( 8) << "dE(MeV)" << " " + << std::setw( 8) << "StepLeng" << " " << std::setw( 9) << "TrackLeng" << " " + << std::setw(11) << "NextVolume" << " " << std::setw( 8) << "ProcName" << G4endl; +#endif + } + G4cout << std::setw( 5) << fTrack->GetCurrentStepNumber() << " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().x() , "Length") << " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().y() , "Length") << " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().z() , "Length") << " " + << std::setw( 9) << G4BestUnit(fTrack->GetKineticEnergy() , "Energy") << " " + << std::setw( 8) << G4BestUnit(fStep->GetTotalEnergyDeposit(), "Energy") << " " + << std::setw( 8) << G4BestUnit(fStep->GetStepLength() , "Length") << " " + << std::setw( 9) << G4BestUnit(fTrack->GetTrackLength() , "Length") << " "; + + // Put cut comment here + if( fTrack->GetNextVolume() != 0 ) { + G4cout << std::setw(11) << fTrack->GetNextVolume()->GetName() << " "; + } else { + G4cout << std::setw(11) << "OutOfWorld" << " "; + } + if(fStep->GetPostStepPoint()->GetProcessDefinedStep() != 0){ + G4cout << fStep->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName(); + } else { + G4cout << "User Limit"; + } + 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( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z() , "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy() , "Energy")<< " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + G4cout << " :-----------------------------" << "----------------------------------" + << "-- EndOf2ndaries Info ---------------" << G4endl; + } + } + } + G4cout.precision(prec); +} +// Put cut comment here if( fStepStatus != fWorldBoundary){ + +//////////////////////////////////////////// +void G4SteppingVerbose::DPSLStarted() +//////////////////////////////////////////// +{ + if(Silent==1){ return; } + CopyState(); + + if( verboseLevel > 5 ){ + G4cout << G4endl << " >>DefinePhysicalStepLength (List of proposed StepLengths): " << G4endl; + } +} +////////////////////////////////////////////// +void G4SteppingVerbose::DPSLUserLimit() +////////////////////////////////////////////// +{ + if(Silent==1){ return; } + CopyState(); + + if( verboseLevel > 5 ){ + G4cout << G4endl << G4endl; + G4cout << "=== Defined Physical Step Length (DPSL)" << G4endl; + G4cout << " ++ProposedStep(UserLimit) = " << std::setw( 9) << physIntLength + << " : ProcName = User defined maximum allowed Step" << G4endl; + } +} +///////////////////////////////////////////// +void G4SteppingVerbose::DPSLPostStep() +///////////////////////////////////////////// +{ + if(Silent==1){ return; } + CopyState(); + + if( verboseLevel > 5 ){ + G4cout << " ++ProposedStep(PostStep ) = " << std::setw( 9) << physIntLength + << " : ProcName = " << fCurrentProcess->GetProcessName() << " ("; + if(fCondition==ExclusivelyForced){ + G4cout << "ExclusivelyForced)" << G4endl; + } + else if(fCondition==StronglyForced){ + G4cout << "StronglyForced)" << G4endl; + } + else if(fCondition==Conditionally){ + G4cout << "Conditionally)" << G4endl; + } + else if(fCondition==Forced){ + G4cout << "Forced)" << G4endl; + } + else{ + G4cout << "No ForceCondition)" << G4endl; + } + } +} +///////////////////////////////////////////// +void G4SteppingVerbose::DPSLAlongStep() +///////////////////////////////////////////// +{ + if(Silent==1){ return; } + CopyState(); + + if( verboseLevel > 5 ){ + G4cout << " ++ProposedStep(AlongStep) = " + << std::setw( 9) << G4BestUnit(physIntLength , "Length") + << " : ProcName = " + << fCurrentProcess->GetProcessName() + << " ("; + if(fGPILSelection==CandidateForSelection){ + G4cout << "CandidateForSelection)" << G4endl; + } + else if(fGPILSelection==NotCandidateForSelection){ + G4cout << "NotCandidateForSelection)" << G4endl; + } + else{ + G4cout << "?!?)" << G4endl; + } + } +} + + +//////////////////////////////////////////////// +void G4SteppingVerbose::TrackingStarted() +//////////////////////////////////////////////// +{ + if(Silent==1){ return; } + + CopyState(); + + G4int prec = G4cout.precision(3); + if( verboseLevel > 0 ){ + +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << std::setw( 5) << "Step#" << " " + << std::setw( 8) << "X" << " " + << std::setw( 8) << "Y" << " " + << std::setw( 8) << "Z" << " " + << std::setw( 9) << "KineE" << " " + << std::setw( 8) << "dE" << " " + << std::setw(12) << "StepLeng" << " " + << std::setw(12) << "TrackLeng" << " " + << std::setw(12) << "NextVolume" << " " + << std::setw( 8) << "ProcName" << G4endl; +#else + G4cout << std::setw( 5) << "Step#" << " " + << std::setw( 8) << "X(mm)" << " " + << std::setw( 8) << "Y(mm)" << " " + << std::setw( 8) << "Z(mm)" << " " + << std::setw( 9) << "KinE(MeV)" << " " + << std::setw( 8) << "dE(MeV)" << " " + << std::setw( 8) << "StepLeng" << " " + << std::setw( 9) << "TrackLeng" << " " + << std::setw(11) << "NextVolume" << " " + << std::setw( 8) << "ProcName" << G4endl; +#endif + + G4cout << std::setw( 5) << fTrack->GetCurrentStepNumber() << " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().x(),"Length")<< " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().y(),"Length") << " " + << std::setw( 8) << G4BestUnit(fTrack->GetPosition().z(),"Length")<< " " + << std::setw( 9) << G4BestUnit(fTrack->GetKineticEnergy(),"Energy")<< " " + << std::setw( 8) << G4BestUnit(fStep->GetTotalEnergyDeposit(),"Energy") << " " + << std::setw( 8) << G4BestUnit(fStep->GetStepLength(),"Length")<< " " + << std::setw( 9) << G4BestUnit(fTrack->GetTrackLength(),"Length") << " "; + + if(fTrack->GetNextVolume()){ + G4cout << std::setw(11) << fTrack->GetNextVolume()->GetName() << " "; + } else { + G4cout << std::setw(11) << "OutOfWorld" << " "; + } + G4cout << "initStep" << G4endl; + } + G4cout.precision(prec); +} +////////////////////////////////////////////////////// +void G4SteppingVerbose::AlongStepDoItOneByOne() +////////////////////////////////////////////////////// +{ + if(Silent==1){ return; } + + CopyState(); + + if(verboseLevel >= 4){ + G4cout << G4endl; + G4cout << " >>AlongStepDoIt (process by process): " + << " Process Name = " + << fCurrentProcess->GetProcessName() << G4endl; + + ShowStep(); + G4cout << " " + << "!Note! Safety of PostStep is only valid " + << "after all DoIt invocations." + << G4endl; + + VerboseParticleChange(); + G4cout << G4endl; + + G4cout << " ++List of secondaries generated " + << "(x,y,z,kE,t,PID):" + << " No. of secodaries = " + << fN2ndariesAlongStepDoIt << G4endl; + + if(fN2ndariesAlongStepDoIt>0){ + for(size_t lp1=(*fSecondary).size()-fN2ndariesAlongStepDoIt; lp1<(*fSecondary).size(); lp1++){ + G4cout << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy() , "Energy")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetGlobalTime() , "Time")<< " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + } + } +} +////////////////////////////////////////////////////// +void G4SteppingVerbose::PostStepDoItOneByOne() +////////////////////////////////////////////////////// +{ + if(Silent==1){ return; } + + CopyState(); + + if(verboseLevel >= 4){ + G4cout << G4endl; + G4cout << " >>PostStepDoIt (process by process): " + << " Process Name = " + << fCurrentProcess->GetProcessName() << G4endl; + + ShowStep(); + G4cout << G4endl; + VerboseParticleChange(); + G4cout << G4endl; + + G4cout << " ++List of secondaries generated " + << "(x,y,z,kE,t,PID):" + << " No. of secodaries = " + << fN2ndariesPostStepDoIt << G4endl; + + if(fN2ndariesPostStepDoIt>0){ + for(size_t lp1=(*fSecondary).size()-fN2ndariesPostStepDoIt; lp1<(*fSecondary).size(); lp1++){ + G4cout << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().x() , "Length")<< " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().y(), "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetPosition().z(), "Length") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetKineticEnergy(), "Energy") << " " + << std::setw( 9) + << G4BestUnit((*fSecondary)[lp1]->GetGlobalTime(), "Time") << " " + << std::setw(18) + << (*fSecondary)[lp1]->GetDefinition()->GetParticleName() << G4endl; + } + } + } +} + + +////////////////////////////////////// +void G4SteppingVerbose::VerboseTrack() +////////////////////////////////////// +{ + if(Silent==1){ return; } + + CopyState(); +// Show header + G4cout << G4endl; + G4cout << " ++G4Track Information " << G4endl; + G4int prec = G4cout.precision(3); + + + G4cout << " -----------------------------------------------" + << G4endl; + G4cout << " G4Track Information " << std::setw(20) << G4endl; + G4cout << " -----------------------------------------------" + << G4endl; + + G4cout << " Step number : " + << std::setw(20) << fTrack->GetCurrentStepNumber() + << G4endl; +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << " Position - x : " + << std::setw(20) << G4BestUnit(fTrack->GetPosition().x(), "Length") + << G4endl; + G4cout << " Position - y : " + << std::setw(20) << G4BestUnit(fTrack->GetPosition().y(), "Length") + << G4endl; + G4cout << " Position - z : " + << std::setw(20) << G4BestUnit(fTrack->GetPosition().z(), "Length") + << G4endl; + G4cout << " Global Time : " + << std::setw(20) << G4BestUnit(fTrack->GetGlobalTime(), "Time") + << G4endl; + G4cout << " Local Time : " + << std::setw(20) << G4BestUnit(fTrack->GetLocalTime(), "Time") + << G4endl; +#else + G4cout << " Position - x (mm) : " + << std::setw(20) << fTrack->GetPosition().x() /mm + << G4endl; + G4cout << " Position - y (mm) : " + << std::setw(20) << fTrack->GetPosition().y() /mm + << G4endl; + G4cout << " Position - z (mm) : " + << std::setw(20) << fTrack->GetPosition().z() /mm + << G4endl; + G4cout << " Global Time (ns) : " + << std::setw(20) << fTrack->GetGlobalTime() /ns + << G4endl; + G4cout << " Local Time (ns) : " + << std::setw(20) << fTrack->GetLocalTime() /ns + << G4endl; +#endif + G4cout << " Momentum Direct - x : " + << std::setw(20) << fTrack->GetMomentumDirection().x() + << G4endl; + G4cout << " Momentum Direct - y : " + << std::setw(20) << fTrack->GetMomentumDirection().y() + << G4endl; + G4cout << " Momentum Direct - z : " + << std::setw(20) << fTrack->GetMomentumDirection().z() + << G4endl; +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << " Kinetic Energy : " +#else + G4cout << " Kinetic Energy (MeV): " +#endif + << std::setw(20) << G4BestUnit(fTrack->GetKineticEnergy(), "Energy") + << G4endl; + G4cout << " Polarization - x : " + << std::setw(20) << fTrack->GetPolarization().x() + << G4endl; + G4cout << " Polarization - y : " + << std::setw(20) << fTrack->GetPolarization().y() + << G4endl; + G4cout << " Polarization - z : " + << std::setw(20) << fTrack->GetPolarization().z() + << G4endl; + G4cout << " Track Length : " + << std::setw(20) << G4BestUnit(fTrack->GetTrackLength(), "Length") + << G4endl; + G4cout << " Track ID # : " + << std::setw(20) << fTrack->GetTrackID() + << G4endl; + G4cout << " Parent Track ID # : " + << std::setw(20) << fTrack->GetParentID() + << G4endl; + G4cout << " Next Volume : " + << std::setw(20); + if( fTrack->GetNextVolume() != 0 ) { + G4cout << fTrack->GetNextVolume()->GetName() << " "; + } else { + G4cout << "OutOfWorld" << " "; + } + G4cout << G4endl; + G4cout << " Track Status : " + << std::setw(20); + if( fTrack->GetTrackStatus() == fAlive ){ + G4cout << " Alive"; + } else if( fTrack->GetTrackStatus() == fStopButAlive ){ + G4cout << " StopButAlive"; + } else if( fTrack->GetTrackStatus() == fStopAndKill ){ + G4cout << " StopAndKill"; + } else if( fTrack->GetTrackStatus() == fKillTrackAndSecondaries ){ + G4cout << " KillTrackAndSecondaries"; + } else if( fTrack->GetTrackStatus() == fSuspend ){ + G4cout << " Suspend"; + } else if( fTrack->GetTrackStatus() == fPostponeToNextEvent ){ + G4cout << " PostponeToNextEvent"; + } + G4cout << G4endl; +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << " Vertex - x : " + << std::setw(20) << G4BestUnit(fTrack->GetVertexPosition().x(),"Length") + << G4endl; + G4cout << " Vertex - y : " + << std::setw(20) << G4BestUnit(fTrack->GetVertexPosition().y(),"Length") + << G4endl; + G4cout << " Vertex - z : " + << std::setw(20) << G4BestUnit(fTrack->GetVertexPosition().z(),"Length") + << G4endl; +#else + G4cout << " Vertex - x (mm) : " + << std::setw(20) << fTrack->GetVertexPosition().x()/mm + << G4endl; + G4cout << " Vertex - y (mm) : " + << std::setw(20) << fTrack->GetVertexPosition().y()/mm + << G4endl; + G4cout << " Vertex - z (mm) : " + << std::setw(20) << fTrack->GetVertexPosition().z()/mm + << G4endl; +#endif + G4cout << " Vertex - Px (MomDir): " + << std::setw(20) << fTrack->GetVertexMomentumDirection().x() + << G4endl; + G4cout << " Vertex - Py (MomDir): " + << std::setw(20) << fTrack->GetVertexMomentumDirection().y() + << G4endl; + G4cout << " Vertex - Pz (MomDir): " + << std::setw(20) << fTrack->GetVertexMomentumDirection().z() + << G4endl; +#ifdef G4_USE_G4BESTUNIT_FOR_VERBOSE + G4cout << " Vertex - KineE : " +#else + G4cout << " Vertex - KineE (MeV): " +#endif + << std::setw(20) << G4BestUnit(fTrack->GetVertexKineticEnergy(),"Energy") + << G4endl; + + G4cout << " Creator Process : " + << std::setw(20); + if( fTrack->GetCreatorProcess() == 0){ + G4cout << " Event Generator" << G4endl; + } else { + G4cout << fTrack->GetCreatorProcess()->GetProcessName() << G4endl; + } + + G4cout << " -----------------------------------------------" + << G4endl; + + G4cout.precision(prec); +} + + +/////////////////////////////////////////////// +void G4SteppingVerbose::VerboseParticleChange() +/////////////////////////////////////////////// +{ + if(Silent==1){ return; } +// Show header + G4cout << G4endl; + G4cout << " ++G4ParticleChange Information " << G4endl; + fParticleChange->DumpInfo(); +} +///////////////////////////////////////// +void G4SteppingVerbose::ShowStep() const +//////////////////////////////////////// +{ + if(Silent==1){ return; } + G4String volName; + G4int oldprc; + +// Show header + G4cout << G4endl; + G4cout << " ++G4Step Information " << G4endl; + oldprc = G4cout.precision(16); + +// Show G4Step specific information + G4cout << " Address of G4Track : " << fStep->GetTrack() << G4endl; + G4cout << " Step Length (mm) : " << fStep->GetTrack()->GetStepLength() << G4endl; + G4cout << " Energy Deposit (MeV) : " << fStep->GetTotalEnergyDeposit() << G4endl; + +// Show G4StepPoint specific information + G4cout << " -------------------------------------------------------" + << "----------------" << G4endl; + G4cout << " StepPoint Information " << std::setw(20) << "PreStep" + << std::setw(20) << "PostStep" << G4endl; + G4cout << " -------------------------------------------------------" + << "----------------" << G4endl; + G4cout << " Position - x (mm) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPosition().x() + << std::setw(20) << fStep->GetPostStepPoint()->GetPosition().x() << G4endl; + G4cout << " Position - y (mm) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPosition().y() + << std::setw(20) << fStep->GetPostStepPoint()->GetPosition().y() << G4endl; + G4cout << " Position - z (mm) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPosition().z() + << std::setw(20) << fStep->GetPostStepPoint()->GetPosition().z() << G4endl; + G4cout << " Global Time (ns) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetGlobalTime() + << std::setw(20) << fStep->GetPostStepPoint()->GetGlobalTime() << G4endl; + G4cout << " Local Time (ns) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetLocalTime() + << std::setw(20) << fStep->GetPostStepPoint()->GetLocalTime() << G4endl; + G4cout << " Proper Time (ns) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetProperTime() + << std::setw(20) << fStep->GetPostStepPoint()->GetProperTime() << G4endl; + G4cout << " Momentum Direct - x : " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentumDirection().x() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentumDirection().x() << G4endl; + G4cout << " Momentum Direct - y : " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentumDirection().y() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentumDirection().y() << G4endl; + G4cout << " Momentum Direct - z : " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentumDirection().z() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentumDirection().z() << G4endl; + G4cout << " Momentum - x (MeV/c): " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentum().x() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentum().x() << G4endl; + G4cout << " Momentum - y (MeV/c): " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentum().y() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentum().y() << G4endl; + G4cout << " Momentum - z (MeV/c): " + << std::setw(20) << fStep->GetPreStepPoint()->GetMomentum().z() + << std::setw(20) << fStep->GetPostStepPoint()->GetMomentum().z() << G4endl; + G4cout << " Total Energy (MeV) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetTotalEnergy() + << std::setw(20) << fStep->GetPostStepPoint()->GetTotalEnergy() << G4endl; + G4cout << " Kinetic Energy (MeV): " + << std::setw(20) << fStep->GetPreStepPoint()->GetKineticEnergy() + << std::setw(20) << fStep->GetPostStepPoint()->GetKineticEnergy() << G4endl; + G4cout << " Velocity (mm/ns) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetVelocity() + << std::setw(20) << fStep->GetPostStepPoint()->GetVelocity() << G4endl; + G4cout << " Volume Name : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPhysicalVolume()->GetName(); + if (fStep->GetPostStepPoint()->GetPhysicalVolume()) + { + volName = fStep->GetPostStepPoint()->GetPhysicalVolume()->GetName(); + } + else + { + volName = "OutOfWorld"; + } + G4cout << std::setw(20) << volName << G4endl; + G4cout << " Safety (mm) : " + << std::setw(20) << fStep->GetPreStepPoint()->GetSafety() + << std::setw(20) << fStep->GetPostStepPoint()->GetSafety() << G4endl; + G4cout << " Polarization - x : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPolarization().x() + << std::setw(20) << fStep->GetPostStepPoint()->GetPolarization().x() << G4endl; + G4cout << " Polarization - y : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPolarization().y() + << std::setw(20) << fStep->GetPostStepPoint()->GetPolarization().y() << G4endl; + G4cout << " Polarization - Z : " + << std::setw(20) << fStep->GetPreStepPoint()->GetPolarization().z() + << std::setw(20) << fStep->GetPostStepPoint()->GetPolarization().z() << G4endl; + G4cout << " Weight : " + << std::setw(20) << fStep->GetPreStepPoint()->GetWeight() + << std::setw(20) << fStep->GetPostStepPoint()->GetWeight() << G4endl; + G4cout << " Step Status : " ; + G4StepStatus tStepStatus = fStep->GetPreStepPoint()->GetStepStatus(); + if( tStepStatus == fGeomBoundary ){ + G4cout << std::setw(20) << "Geom Limit"; + } else if ( tStepStatus == fAlongStepDoItProc ){ + G4cout << std::setw(20) << "AlongStep Proc."; + } else if ( tStepStatus == fPostStepDoItProc ){ + G4cout << std::setw(20) << "PostStep Proc"; + } else if ( tStepStatus == fAtRestDoItProc ){ + G4cout << std::setw(20) << "AtRest Proc"; + } else if ( tStepStatus == fUndefined ){ + G4cout << std::setw(20) << "Undefined"; + } + + tStepStatus = fStep->GetPostStepPoint()->GetStepStatus(); + if( tStepStatus == fGeomBoundary ){ + G4cout << std::setw(20) << "Geom Limit"; + } else if ( tStepStatus == fAlongStepDoItProc ){ + G4cout << std::setw(20) << "AlongStep Proc."; + } else if ( tStepStatus == fPostStepDoItProc ){ + G4cout << std::setw(20) << "PostStep Proc"; + } else if ( tStepStatus == fAtRestDoItProc ){ + G4cout << std::setw(20) << "AtRest Proc"; + } else if ( tStepStatus == fUndefined ){ + G4cout << std::setw(20) << "Undefined"; + } + + G4cout << G4endl; + G4cout << " Process defined Step: " ; + if( fStep->GetPreStepPoint()->GetProcessDefinedStep() == 0 ){ + G4cout << std::setw(20) << "Undefined"; + } else { + G4cout << std::setw(20) << fStep->GetPreStepPoint()->GetProcessDefinedStep()->GetProcessName(); + } + if( fStep->GetPostStepPoint()->GetProcessDefinedStep() == 0){ + G4cout << std::setw(20) << "Undefined"; + } else { + G4cout << std::setw(20) << fStep->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName(); + } + G4cout.precision(oldprc); + + G4cout << G4endl; + G4cout << " -------------------------------------------------------" + << "----------------" << G4endl; +} + + diff --git a/src/G4.10.04.p02fixes/G4Transportation.cc b/src/G4.10.04.p02fixes/G4Transportation.cc new file mode 100644 index 0000000..301f558 --- /dev/null +++ b/src/G4.10.04.p02fixes/G4Transportation.cc @@ -0,0 +1,821 @@ +// +// ******************************************************************** +// * 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: G4Transportation.cc 2011/06/10 16:19:46 japost Exp japost $ +// +// ------------------------------------------------------------ +// GEANT 4 include file implementation +// +// ------------------------------------------------------------ +// +// This class is a process responsible for the transportation of +// a particle, ie the geometrical propagation that encounters the +// geometrical sub-volumes of the detectors. +// +// It is also tasked with the key role of proposing the "isotropic safety", +// which will be used to update the post-step point's safety. +// +// ======================================================================= +// Modified: +// 10 Jan 2015, M.Kelsey: Use G4DynamicParticle mass, NOT PDGMass +// 28 Oct 2011, P.Gumpl./J.Ap: Detect gravity field, use magnetic moment +// 20 Nov 2008, J.Apostolakis: Push safety to helper - after ComputeSafety +// 9 Nov 2007, J.Apostolakis: Flag for short steps, push safety to helper +// 19 Jan 2006, P.MoraDeFreitas: Fix for suspended tracks (StartTracking) +// 11 Aug 2004, M.Asai: Add G4VSensitiveDetector* for updating stepPoint. +// 21 June 2003, J.Apostolakis: Calling field manager with +// track, to enable it to configure its accuracy +// 13 May 2003, J.Apostolakis: Zero field areas now taken into +// account correclty in all cases (thanks to W Pokorski). +// 29 June 2001, J.Apostolakis, D.Cote-Ahern, P.Gumplinger: +// correction for spin tracking +// 20 Febr 2001, J.Apostolakis: update for new FieldTrack +// 22 Sept 2000, V.Grichine: update of Kinetic Energy +// Created: 19 March 1997, J. Apostolakis +// ======================================================================= + +#include "G4Transportation.hh" +#include "G4TransportationProcessType.hh" + +#include "G4PhysicalConstants.hh" +#include "G4SystemOfUnits.hh" +#include "G4ProductionCutsTable.hh" +#include "G4ParticleTable.hh" + +#include "G4ChargeState.hh" +#include "G4EquationOfMotion.hh" + +#include "G4FieldManagerStore.hh" + +class G4VSensitiveDetector; + +G4bool G4Transportation::fUseMagneticMoment=false; + +// #define G4DEBUG_TRANSPORT 1 + +////////////////////////////////////////////////////////////////////////// +// +// Constructor + +G4Transportation::G4Transportation( G4int verbosity ) + : G4VProcess( G4String("Transportation"), fTransportation ), + fTransportEndPosition( 0.0, 0.0, 0.0 ), + fTransportEndMomentumDir( 0.0, 0.0, 0.0 ), + fTransportEndKineticEnergy( 0.0 ), + fTransportEndSpin( 0.0, 0.0, 0.0 ), + fMomentumChanged(true), + fEndGlobalTimeComputed(false), + fCandidateEndGlobalTime(0.0), + fParticleIsLooping( false ), + fNewTrack( true ), + fFirstStepInVolume( true ), + fLastStepInVolume( false ), + fGeometryLimitedStep(true), + fFieldExertedForce( false ), + fPreviousSftOrigin( 0.,0.,0. ), + fPreviousSafety( 0.0 ), + // fParticleChange(), + fEndPointDistance( -1.0 ), + fThreshold_Warning_Energy( 100 * MeV ), + fThreshold_Important_Energy( 250 * MeV ), + fThresholdTrials( 10 ), + fNoLooperTrials( 0 ), + fSumEnergyKilled( 0.0 ), fMaxEnergyKilled( 0.0 ), + fShortStepOptimisation( false ) // Old default: true (=fast short steps) +{ + // set Process Sub Type + SetProcessSubType(static_cast(TRANSPORTATION)); + pParticleChange= &fParticleChange; // Required to conform to G4VProcess + SetVerboseLevel(verbosity); + + G4TransportationManager* transportMgr ; + + transportMgr = G4TransportationManager::GetTransportationManager() ; + + fLinearNavigator = transportMgr->GetNavigatorForTracking() ; + + fFieldPropagator = transportMgr->GetPropagatorInField() ; + + fpSafetyHelper = transportMgr->GetSafetyHelper(); // New + + // Cannot determine whether a field exists here, as it would + // depend on the relative order of creating the detector's + // field and this process. That order is not guaranted. + // Instead later the method DoesGlobalFieldExist() is called + + static G4ThreadLocal G4TouchableHandle* pNullTouchableHandle = 0; + if ( !pNullTouchableHandle) { pNullTouchableHandle = new G4TouchableHandle; } + fCurrentTouchableHandle = *pNullTouchableHandle; + // Points to (G4VTouchable*) 0 + +#ifdef G4VERBOSE + if( verboseLevel > 0) + { + G4cout << " G4Transportation constructor> set fShortStepOptimisation to "; + if ( fShortStepOptimisation ) G4cout << "true" << G4endl; + else G4cout << "false" << G4endl; + } +#endif +} + +////////////////////////////////////////////////////////////////////////// + +G4Transportation::~G4Transportation() +{ + if( (verboseLevel > 0) && (fSumEnergyKilled > 0.0 ) ) + { + G4cout << " G4Transportation: Statistics for looping particles " << G4endl; + G4cout << " Sum of energy of loopers killed: " << fSumEnergyKilled << G4endl; + G4cout << " Max energy of loopers killed: " << fMaxEnergyKilled << G4endl; + } +} + +////////////////////////////////////////////////////////////////////////// +// +// Responsibilities: +// Find whether the geometry limits the Step, and to what length +// Calculate the new value of the safety and return it. +// Store the final time, position and momentum. + +G4double G4Transportation:: +AlongStepGetPhysicalInteractionLength( const G4Track& track, + G4double, // previousStepSize + G4double currentMinimumStep, + G4double& currentSafety, + G4GPILSelection* selection ) +{ + G4double geometryStepLength= -1.0, newSafety= -1.0; + fParticleIsLooping = false ; + + // Initial actions moved to StartTrack() + // -------------------------------------- + // Note: in case another process changes touchable handle + // it will be necessary to add here (for all steps) + // fCurrentTouchableHandle = aTrack->GetTouchableHandle(); + + // GPILSelection is set to defaule value of CandidateForSelection + // It is a return value + // + *selection = CandidateForSelection ; + + fFirstStepInVolume= fNewTrack || fLastStepInVolume; + fLastStepInVolume= false; + fNewTrack = false; + + // Get initial Energy/Momentum of the track + // + const G4DynamicParticle* pParticle = track.GetDynamicParticle() ; + const G4ParticleDefinition* pParticleDef = pParticle->GetDefinition() ; + G4ThreeVector startMomentumDir = pParticle->GetMomentumDirection() ; + G4ThreeVector startPosition = track.GetPosition() ; + + // G4double theTime = track.GetGlobalTime() ; + + // The Step Point safety can be limited by other geometries and/or the + // assumptions of any process - it's not always the geometrical safety. + // We calculate the starting point's isotropic safety here. + // + G4ThreeVector OriginShift = startPosition - fPreviousSftOrigin ; + G4double MagSqShift = OriginShift.mag2() ; + if( MagSqShift >= sqr(fPreviousSafety) ) + { + currentSafety = 0.0 ; + } + else + { + currentSafety = fPreviousSafety - std::sqrt(MagSqShift) ; + } + + // Is the particle charged or has it a magnetic moment? + // + G4double particleCharge = pParticle->GetCharge() ; + G4double magneticMoment = pParticle->GetMagneticMoment() ; + G4double restMass = pParticle->GetMass() ; + + fGeometryLimitedStep = false ; + // fEndGlobalTimeComputed = false ; + + // There is no need to locate the current volume. It is Done elsewhere: + // On track construction + // By the tracking, after all AlongStepDoIts, in "Relocation" + + // Check if the particle has a force, EM or gravitational, exerted on it + // + G4FieldManager* fieldMgr=0; + G4bool fieldExertsForce = false ; + + G4bool gravityOn = false; + G4bool fieldExists= false; // Field is not 0 (null pointer) + + fieldMgr = fFieldPropagator->FindAndSetFieldManager( track.GetVolume() ); + if( fieldMgr != 0 ) + { + // Message the field Manager, to configure it for this track + fieldMgr->ConfigureForTrack( &track ); + // Is here to allow a transition from no-field pointer + // to finite field (non-zero pointer). + + // If the field manager has no field ptr, the field is zero + // by definition ( = there is no field ! ) + const G4Field* ptrField= fieldMgr->GetDetectorField(); + fieldExists = (ptrField!=0) ; + if( fieldExists ) + { + gravityOn= ptrField->IsGravityActive(); + + if( (particleCharge != 0.0) + || (fUseMagneticMoment && (magneticMoment != 0.0) ) + || (gravityOn && (restMass != 0.0) ) + ) + { + fieldExertsForce = fieldExists; + } + } + } + // G4cout << " G4Transport: field exerts force= " << fieldExertsForce + // << " fieldMgr= " << fieldMgr << G4endl; + fFieldExertedForce = fieldExertsForce; + + if( !fieldExertsForce ) + { + G4double linearStepLength ; + if( fShortStepOptimisation && (currentMinimumStep <= currentSafety) ) + { + // The Step is guaranteed to be taken + // + geometryStepLength = currentMinimumStep ; + fGeometryLimitedStep = false ; + } + else + { + // Find whether the straight path intersects a volume + // + linearStepLength = fLinearNavigator->ComputeStep( startPosition, + startMomentumDir, + currentMinimumStep, + newSafety) ; + // Remember last safety origin & value. + // + fPreviousSftOrigin = startPosition ; + fPreviousSafety = newSafety ; + fpSafetyHelper->SetCurrentSafety( newSafety, startPosition); + + currentSafety = newSafety ; + + fGeometryLimitedStep= (linearStepLength <= currentMinimumStep); + if( fGeometryLimitedStep ) + { + // The geometry limits the Step size (an intersection was found.) + geometryStepLength = linearStepLength ; + } + else + { + // The full Step is taken. + geometryStepLength = currentMinimumStep ; + } + } + fEndPointDistance = geometryStepLength ; + + // Calculate final position + // + fTransportEndPosition = startPosition+geometryStepLength*startMomentumDir ; + + // Momentum direction, energy and polarisation are unchanged by transport + // + fTransportEndMomentumDir = startMomentumDir ; + fTransportEndKineticEnergy = track.GetKineticEnergy() ; + fTransportEndSpin = track.GetPolarization(); + fParticleIsLooping = false ; + fMomentumChanged = false ; + fEndGlobalTimeComputed = false ; + } + else // A field exerts force + { + G4double momentumMagnitude = pParticle->GetTotalMomentum() ; + G4ThreeVector EndUnitMomentum ; + G4double lengthAlongCurve ; + + G4ChargeState chargeState(particleCharge, // The charge can change (dynamic) + magneticMoment, + pParticleDef->GetPDGSpin() ); + // For insurance, could set it again + // chargeState.SetPDGSpin(pParticleDef->GetPDGSpin() ); // Provisionally in same object + + G4EquationOfMotion* equationOfMotion = fFieldPropagator->GetCurrentEquationOfMotion(); + + equationOfMotion->SetChargeMomentumMass( chargeState, + momentumMagnitude, + restMass); + + G4FieldTrack aFieldTrack = G4FieldTrack( startPosition, + track.GetGlobalTime(), // Lab. + // track.GetProperTime(), // Particle rest frame + track.GetMomentumDirection(), + track.GetKineticEnergy(), + restMass, + particleCharge, + track.GetPolarization(), + pParticleDef->GetPDGMagneticMoment(), + 0.0, // Length along track + pParticleDef->GetPDGSpin() + ) ; + + if( currentMinimumStep > 0 ) + { + // Do the Transport in the field (non recti-linear) + // + lengthAlongCurve = fFieldPropagator->ComputeStep( aFieldTrack, + currentMinimumStep, + currentSafety, + track.GetVolume() ) ; + + fGeometryLimitedStep= fFieldPropagator->IsLastStepInVolume(); + // It is possible that step was reduced in PropagatorInField due to previous zero steps + // To cope with case that reduced step is taken in full, we must rely on PiF to obtain this + // value. + + geometryStepLength = std::min( lengthAlongCurve, currentMinimumStep ); + + // Remember last safety origin & value. + // + fPreviousSftOrigin = startPosition ; + fPreviousSafety = currentSafety ; + fpSafetyHelper->SetCurrentSafety( currentSafety, startPosition); + } + else + { + geometryStepLength = lengthAlongCurve= 0.0 ; + fGeometryLimitedStep = false ; + } + + // Get the End-Position and End-Momentum (Dir-ection) + // + fTransportEndPosition = aFieldTrack.GetPosition() ; + + // Momentum: Magnitude and direction can be changed too now ... + // + fMomentumChanged = true ; + fTransportEndMomentumDir = aFieldTrack.GetMomentumDir() ; + + fTransportEndKineticEnergy = aFieldTrack.GetKineticEnergy() ; + + if( fFieldPropagator->GetCurrentFieldManager()->DoesFieldChangeEnergy() ) + { + // If the field can change energy, then the time must be integrated + // - so this should have been updated + // + fCandidateEndGlobalTime = aFieldTrack.GetLabTimeOfFlight(); + fEndGlobalTimeComputed = true; + + // was ( fCandidateEndGlobalTime != track.GetGlobalTime() ); + // a cleaner way is to have FieldTrack knowing whether time is updated. + } + else + { + // The energy should be unchanged by field transport, + // - so the time changed will be calculated elsewhere + // + fEndGlobalTimeComputed = false; + + // Check that the integration preserved the energy + // - and if not correct this! + G4double startEnergy= track.GetKineticEnergy(); + G4double endEnergy= fTransportEndKineticEnergy; + + static G4ThreadLocal G4int no_inexact_steps=0, no_large_ediff; + G4double absEdiff = std::fabs(startEnergy- endEnergy); + if( absEdiff > perMillion * endEnergy ) + { + no_inexact_steps++; + // Possible statistics keeping here ... + } + if( verboseLevel > 1 ) + { + if( std::fabs(startEnergy- endEnergy) > perThousand * endEnergy ) + { + static G4ThreadLocal G4int no_warnings= 0, warnModulo=1, + moduloFactor= 10; + no_large_ediff ++; + if( (no_large_ediff% warnModulo) == 0 ) + { + no_warnings++; + G4cout << "WARNING - G4Transportation::AlongStepGetPIL() " + << " Energy change in Step is above 1^-3 relative value. " << G4endl + << " Relative change in 'tracking' step = " + << std::setw(15) << (endEnergy-startEnergy)/startEnergy << G4endl + << " Starting E= " << std::setw(12) << startEnergy / MeV << " MeV " << G4endl + << " Ending E= " << std::setw(12) << endEnergy / MeV << " MeV " << G4endl; + G4cout << " Energy has been corrected -- however, review" + << " field propagation parameters for accuracy." << G4endl; + if( (verboseLevel > 2 ) || (no_warnings<4) || (no_large_ediff == warnModulo * moduloFactor) ) + { + G4cout << " These include EpsilonStepMax(/Min) in G4FieldManager " + << " which determine fractional error per step for integrated quantities. " << G4endl + << " Note also the influence of the permitted number of integration steps." + << G4endl; + } + G4cerr << "ERROR - G4Transportation::AlongStepGetPIL()" << G4endl + << " Bad 'endpoint'. Energy change detected" + << " and corrected. " + << " Has occurred already " + << no_large_ediff << " times." << G4endl; + if( no_large_ediff == warnModulo * moduloFactor ) + { + warnModulo *= moduloFactor; + } + } + } + } // end of if (verboseLevel) + + // Correct the energy for fields that conserve it + // This - hides the integration error + // - but gives a better physical answer + fTransportEndKineticEnergy= track.GetKineticEnergy(); + } + + fTransportEndSpin = aFieldTrack.GetSpin(); + fParticleIsLooping = fFieldPropagator->IsParticleLooping() ; + fEndPointDistance = (fTransportEndPosition - startPosition).mag() ; + } + + // If we are asked to go a step length of 0, and we are on a boundary + // then a boundary will also limit the step -> we must flag this. + // + if( currentMinimumStep == 0.0 ) + { + if( currentSafety == 0.0 ) { fGeometryLimitedStep = true; } + } + + // Update the safety starting from the end-point, + // if it will become negative at the end-point. + // + if( currentSafety < fEndPointDistance ) + { + if( particleCharge != 0.0 ) + { + G4double endSafety = + fLinearNavigator->ComputeSafety( fTransportEndPosition) ; + currentSafety = endSafety ; + fPreviousSftOrigin = fTransportEndPosition ; + fPreviousSafety = currentSafety ; + fpSafetyHelper->SetCurrentSafety( currentSafety, fTransportEndPosition); + + // Because the Stepping Manager assumes it is from the start point, + // add the StepLength + // + currentSafety += fEndPointDistance ; + +#ifdef G4DEBUG_TRANSPORT + G4cout.precision(12) ; + G4cout << "***G4Transportation::AlongStepGPIL ** " << G4endl ; + G4cout << " Called Navigator->ComputeSafety at " << fTransportEndPosition + << " and it returned safety= " << endSafety << G4endl ; + G4cout << " Adding endpoint distance " << fEndPointDistance + << " to obtain pseudo-safety= " << currentSafety << G4endl ; + } + else + { + G4cout << "***G4Transportation::AlongStepGPIL ** " << G4endl ; + G4cout << " Avoiding call to ComputeSafety : " << G4endl; + G4cout << " charge = " << particleCharge << G4endl; + G4cout << " mag moment = " << magneticMoment << G4endl; +#endif + } + } + + fParticleChange.ProposeTrueStepLength(geometryStepLength) ; + + return geometryStepLength ; +} + +////////////////////////////////////////////////////////////////////////// +// +// Initialize ParticleChange (by setting all its members equal +// to corresponding members in G4Track) + +G4VParticleChange* G4Transportation::AlongStepDoIt( const G4Track& track, + const G4Step& stepData ) +{ + static G4ThreadLocal G4int noCalls=0; + noCalls++; + + fParticleChange.Initialize(track) ; + + // Code for specific process + // + fParticleChange.ProposePosition(fTransportEndPosition) ; + fParticleChange.ProposeMomentumDirection(fTransportEndMomentumDir) ; + fParticleChange.ProposeEnergy(fTransportEndKineticEnergy) ; + fParticleChange.SetMomentumChanged(fMomentumChanged) ; + + fParticleChange.ProposePolarization(fTransportEndSpin); + + G4double deltaTime = 0.0 ; + + // Calculate Lab Time of Flight (ONLY if field Equations used it!) + // G4double endTime = fCandidateEndGlobalTime; + // G4double delta_time = endTime - startTime; + + G4double startTime = track.GetGlobalTime() ; + + if (!fEndGlobalTimeComputed) + { + // The time was not integrated .. make the best estimate possible + // + G4double initialVelocity = stepData.GetPreStepPoint()->GetVelocity(); + G4double stepLength = track.GetStepLength(); + + deltaTime= 0.0; // in case initialVelocity = 0 + if ( initialVelocity > 0.0 ) { deltaTime = stepLength/initialVelocity; } + + fCandidateEndGlobalTime = startTime + deltaTime ; + fParticleChange.ProposeLocalTime( track.GetLocalTime() + deltaTime) ; + } + else + { + deltaTime = fCandidateEndGlobalTime - startTime ; + fParticleChange.ProposeGlobalTime( fCandidateEndGlobalTime ) ; + } + + + // Now Correct by Lorentz factor to get delta "proper" Time + + G4double restMass = track.GetDynamicParticle()->GetMass() ; + G4double deltaProperTime = deltaTime*( restMass/track.GetTotalEnergy() ) ; + + fParticleChange.ProposeProperTime(track.GetProperTime() + deltaProperTime) ; + //fParticleChange. ProposeTrueStepLength( track.GetStepLength() ) ; + + // If the particle is caught looping or is stuck (in very difficult + // boundaries) in a magnetic field (doing many steps) + // THEN this kills it ... + // + if ( fParticleIsLooping ) + { + G4double endEnergy= fTransportEndKineticEnergy; + + if( (endEnergy < fThreshold_Important_Energy) + || (fNoLooperTrials >= fThresholdTrials ) ) + { + // Kill the looping particle + // + fParticleChange.ProposeTrackStatus( fStopAndKill ) ; + + // 'Bare' statistics + fSumEnergyKilled += endEnergy; + if( endEnergy > fMaxEnergyKilled) { fMaxEnergyKilled= endEnergy; } + +#ifdef G4VERBOSE + if( (verboseLevel > 1) && + ( endEnergy > fThreshold_Warning_Energy ) ) + { + G4cout << " G4Transportation is killing track that is looping or stuck " + << G4endl + << " This track has " << track.GetKineticEnergy() / MeV + << " MeV energy." << G4endl; + G4cout << " Number of trials = " << fNoLooperTrials + << " No of calls to AlongStepDoIt = " << noCalls + << G4endl; + } +#endif + fNoLooperTrials=0; + } + else + { + fNoLooperTrials ++; +#ifdef G4VERBOSE + if( (verboseLevel > 2) ) + { + G4cout << " G4Transportation::AlongStepDoIt(): Particle looping - " + << " Number of trials = " << fNoLooperTrials + << " No of calls to = " << noCalls + << G4endl; + } +#endif + } + } + else + { + fNoLooperTrials=0; + } + + // Another (sometimes better way) is to use a user-limit maximum Step size + // to alleviate this problem .. + + // Introduce smooth curved trajectories to particle-change + // + fParticleChange.SetPointerToVectorOfAuxiliaryPoints + (fFieldPropagator->GimmeTrajectoryVectorAndForgetIt() ); + + return &fParticleChange ; +} + +////////////////////////////////////////////////////////////////////////// +// +// This ensures that the PostStep action is always called, +// so that it can do the relocation if it is needed. +// + +G4double G4Transportation:: +PostStepGetPhysicalInteractionLength( const G4Track&, + G4double, // previousStepSize + G4ForceCondition* pForceCond ) +{ + fFieldExertedForce = false; // Not known + *pForceCond = Forced ; + return DBL_MAX ; // was kInfinity ; but convention now is DBL_MAX +} + +///////////////////////////////////////////////////////////////////////////// +// + +G4VParticleChange* G4Transportation::PostStepDoIt( const G4Track& track, + const G4Step& ) +{ + G4TouchableHandle retCurrentTouchable ; // The one to return + G4bool isLastStep= false; + + // Initialize ParticleChange (by setting all its members equal + // to corresponding members in G4Track) + // fParticleChange.Initialize(track) ; // To initialise TouchableChange + + fParticleChange.ProposeTrackStatus(track.GetTrackStatus()) ; + + // If the Step was determined by the volume boundary, + // logically relocate the particle + + if(fGeometryLimitedStep) + { + // fCurrentTouchable will now become the previous touchable, + // and what was the previous will be freed. + // (Needed because the preStepPoint can point to the previous touchable) + + fLinearNavigator->SetGeometricallyLimitedStep() ; + fLinearNavigator-> + LocateGlobalPointAndUpdateTouchableHandle( track.GetPosition(), + track.GetMomentumDirection(), + fCurrentTouchableHandle, + true ) ; + // Check whether the particle is out of the world volume + // If so it has exited and must be killed. + // + if( fCurrentTouchableHandle->GetVolume() == 0 ) + { + fParticleChange.ProposeTrackStatus( fStopAndKill ) ; + } + retCurrentTouchable = fCurrentTouchableHandle ; + fParticleChange.SetTouchableHandle( fCurrentTouchableHandle ) ; + + // Update the Step flag which identifies the Last Step in a volume + if( !fFieldExertedForce ) + isLastStep = fLinearNavigator->ExitedMotherVolume() + | fLinearNavigator->EnteredDaughterVolume() ; + else + isLastStep = fFieldPropagator->IsLastStepInVolume(); + } + else // fGeometryLimitedStep is false + { + // This serves only to move the Navigator's location + // + fLinearNavigator->LocateGlobalPointWithinVolume( track.GetPosition() ) ; + + // The value of the track's current Touchable is retained. + // (and it must be correct because we must use it below to + // overwrite the (unset) one in particle change) + // It must be fCurrentTouchable too ?? + // + fParticleChange.SetTouchableHandle( track.GetTouchableHandle() ) ; + retCurrentTouchable = track.GetTouchableHandle() ; + + isLastStep= false; + } // endif ( fGeometryLimitedStep ) + fLastStepInVolume= isLastStep; + + fParticleChange.ProposeFirstStepInVolume(fFirstStepInVolume); + fParticleChange.ProposeLastStepInVolume(isLastStep); + + const G4VPhysicalVolume* pNewVol = retCurrentTouchable->GetVolume() ; + const G4Material* pNewMaterial = 0 ; + const G4VSensitiveDetector* pNewSensitiveDetector = 0 ; + + if( pNewVol != 0 ) + { + pNewMaterial= pNewVol->GetLogicalVolume()->GetMaterial(); + pNewSensitiveDetector= pNewVol->GetLogicalVolume()->GetSensitiveDetector(); + } + + // ( pNewMaterial ) ; + // ( pNewSensitiveDetector) ; + + fParticleChange.SetMaterialInTouchable( (G4Material *) pNewMaterial ) ; + fParticleChange.SetSensitiveDetectorInTouchable( (G4VSensitiveDetector *) pNewSensitiveDetector ) ; + + const G4MaterialCutsCouple* pNewMaterialCutsCouple = 0; + if( pNewVol != 0 ) + { + pNewMaterialCutsCouple=pNewVol->GetLogicalVolume()->GetMaterialCutsCouple(); + } + + if( pNewVol!=0 && pNewMaterialCutsCouple!=0 && pNewMaterialCutsCouple->GetMaterial()!=pNewMaterial ) + { + // for parametrized volume + // + pNewMaterialCutsCouple = + G4ProductionCutsTable::GetProductionCutsTable() + ->GetMaterialCutsCouple(pNewMaterial, + pNewMaterialCutsCouple->GetProductionCuts()); + } + fParticleChange.SetMaterialCutsCoupleInTouchable( pNewMaterialCutsCouple ); + + // temporarily until Get/Set Material of ParticleChange, + // and StepPoint can be made const. + // Set the touchable in ParticleChange + // this must always be done because the particle change always + // uses this value to overwrite the current touchable pointer. + // + fParticleChange.SetTouchableHandle(retCurrentTouchable) ; + + return &fParticleChange ; +} + +// New method takes over the responsibility to reset the state of G4Transportation +// object at the start of a new track or the resumption of a suspended track. + +void +G4Transportation::StartTracking(G4Track* aTrack) +{ + G4VProcess::StartTracking(aTrack); + fNewTrack= true; + fFirstStepInVolume= true; + fLastStepInVolume= false; + + // The actions here are those that were taken in AlongStepGPIL + // when track.GetCurrentStepNumber()==1 + + // reset safety value and center + // + fPreviousSafety = 0.0 ; + fPreviousSftOrigin = G4ThreeVector(0.,0.,0.) ; + + // reset looping counter -- for motion in field + fNoLooperTrials= 0; + // Must clear this state .. else it depends on last track's value + // --> a better solution would set this from state of suspended track TODO ? + // Was if( aTrack->GetCurrentStepNumber()==1 ) { .. } + + // ChordFinder reset internal state + // + if( fFieldPropagator ) + { + fFieldPropagator->ClearPropagatorState(); + // Resets all state of field propagator class (ONLY) + // including safety values (in case of overlaps and to wipe for first track). + + // G4ChordFinder* chordF= fFieldPropagator->GetChordFinder(); + // if( chordF ) chordF->ResetStepEstimate(); + } + + // Make sure to clear the chord finders of all fields (ie managers) + // + G4FieldManagerStore* fieldMgrStore = G4FieldManagerStore::GetInstance(); + fieldMgrStore->ClearAllChordFindersState(); + + // Update the current touchable handle (from the track's) + // + fCurrentTouchableHandle = aTrack->GetTouchableHandle(); + + // Inform field propagator of new track + fFieldPropagator->PrepareNewTrack(); +} + +#include "G4CoupledTransportation.hh" +G4bool G4Transportation::EnableUseMagneticMoment(G4bool useMoment) +{ + G4bool lastValue= fUseMagneticMoment; + fUseMagneticMoment= useMoment; + G4CoupledTransportation::fUseMagneticMoment= useMoment; + return lastValue; +} diff --git a/src/G4.10.04.p02fixes/G4Tubs.cc b/src/G4.10.04.p02fixes/G4Tubs.cc new file mode 100644 index 0000000..ebcafc9 --- /dev/null +++ b/src/G4.10.04.p02fixes/G4Tubs.cc @@ -0,0 +1,1778 @@ +// +// ******************************************************************** +// * 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: G4Tubs.cc 104316 2017-05-24 13:04:23Z gcosmo $ +// +// +// class G4Tubs +// +// History: +// +// 24.08.16 E.Tcherniaev: reimplemented CalculateExtent() to make use +// of G4BoundingEnvelope +// 05.04.12 M.Kelsey: Use sqrt(r) in GetPointOnSurface() for uniform points +// 02.08.07 T.Nikitina: bug fixed in DistanceToOut(p,v,..) for negative value under sqrt +// for the case: p on the surface and v is tangent to the surface +// 11.05.07 T.Nikitina: bug fixed in DistanceToOut(p,v,..) for phi < 2pi +// 03.05.05 V.Grichine: SurfaceNormal(p) according to J. Apostolakis proposal +// 16.03.05 V.Grichine: SurfaceNormal(p) with edges/corners for boolean +// 20.07.01 V.Grichine: bug fixed in Inside(p) +// 20.02.01 V.Grichine: bug fixed in Inside(p) and CalculateExtent was +// simplified base on G4Box::CalculateExtent +// 07.12.00 V.Grichine: phi-section algorithm was changed in Inside(p) +// 28.11.00 V.Grichine: bug fixed in Inside(p) +// 31.10.00 V.Grichine: assign srd, sphi in Distance ToOut(p,v,...) +// 08.08.00 V.Grichine: more stable roots of 2-equation in DistanceToOut(p,v,..) +// 02.08.00 V.Grichine: point is outside check in Distance ToOut(p) +// 17.05.00 V.Grichine: bugs (#76,#91) fixed in Distance ToOut(p,v,...) +// 31.03.00 V.Grichine: bug fixed in Inside(p) +// 19.11.99 V.Grichine: side = kNull in DistanceToOut(p,v,...) +// 13.10.99 V.Grichine: bugs fixed in DistanceToIn(p,v) +// 28.05.99 V.Grichine: bugs fixed in DistanceToOut(p,v,...) +// 25.05.99 V.Grichine: bugs fixed in DistanceToIn(p,v) +// 23.03.99 V.Grichine: bug fixed in DistanceToIn(p,v) +// 09.10.98 V.Grichine: modifications in DistanceToOut(p,v,...) +// 18.06.98 V.Grichine: n-normalisation in DistanceToOut(p,v) +// +// 1994-95 P.Kent: implementation +// +///////////////////////////////////////////////////////////////////////// + +#include "G4Tubs.hh" + +#if !defined(G4GEOM_USE_UTUBS) + +#include "G4GeomTools.hh" +#include "G4VoxelLimits.hh" +#include "G4AffineTransform.hh" +#include "G4GeometryTolerance.hh" +#include "G4BoundingEnvelope.hh" + +#include "G4VPVParameterisation.hh" + +#include "Randomize.hh" + +#include "meshdefs.hh" + +#include "G4VGraphicsScene.hh" + +using namespace CLHEP; + +///////////////////////////////////////////////////////////////////////// +// +// Constructor - check parameters, convert angles so 02PI then reset to 2PI + +G4Tubs::G4Tubs( const G4String &pName, + G4double pRMin, G4double pRMax, + G4double pDz, + G4double pSPhi, G4double pDPhi ) + : G4CSGSolid(pName), fRMin(pRMin), fRMax(pRMax), fDz(pDz), fSPhi(0), fDPhi(0) +{ + + kRadTolerance = G4GeometryTolerance::GetInstance()->GetRadialTolerance(); + kAngTolerance = G4GeometryTolerance::GetInstance()->GetAngularTolerance(); + + halfCarTolerance=kCarTolerance*0.5; + halfRadTolerance=kRadTolerance*0.5; + halfAngTolerance=kAngTolerance*0.5; + + if (pDz<=0) // Check z-len + { + std::ostringstream message; + message << "Negative Z half-length (" << pDz << ") in solid: " << GetName(); + G4Exception("G4Tubs::G4Tubs()", "GeomSolids0002", FatalException, message); + } + if ( (pRMin >= pRMax) || (pRMin < 0) ) // Check radii + { + std::ostringstream message; + message << "Invalid values for radii in solid: " << GetName() + << G4endl + << " pRMin = " << pRMin << ", pRMax = " << pRMax; + G4Exception("G4Tubs::G4Tubs()", "GeomSolids0002", FatalException, message); + } + + // Check angles + // + CheckPhiAngles(pSPhi, pDPhi); +} + +/////////////////////////////////////////////////////////////////////// +// +// Fake default constructor - sets only member data and allocates memory +// for usage restricted to object persistency. +// +G4Tubs::G4Tubs( __void__& a ) + : G4CSGSolid(a), kRadTolerance(0.), kAngTolerance(0.), + fRMin(0.), fRMax(0.), fDz(0.), fSPhi(0.), fDPhi(0.), + sinCPhi(0.), cosCPhi(0.), cosHDPhiOT(0.), cosHDPhiIT(0.), + sinSPhi(0.), cosSPhi(0.), sinEPhi(0.), cosEPhi(0.), + fPhiFullTube(false), halfCarTolerance(0.), halfRadTolerance(0.), + halfAngTolerance(0.) +{ +} + +////////////////////////////////////////////////////////////////////////// +// +// Destructor + +G4Tubs::~G4Tubs() +{ +} + +////////////////////////////////////////////////////////////////////////// +// +// Copy constructor + +G4Tubs::G4Tubs(const G4Tubs& rhs) + : G4CSGSolid(rhs), + kRadTolerance(rhs.kRadTolerance), kAngTolerance(rhs.kAngTolerance), + fRMin(rhs.fRMin), fRMax(rhs.fRMax), fDz(rhs.fDz), + fSPhi(rhs.fSPhi), fDPhi(rhs.fDPhi), + sinCPhi(rhs.sinCPhi), cosCPhi(rhs.cosCPhi), + cosHDPhiOT(rhs.cosHDPhiOT), cosHDPhiIT(rhs.cosHDPhiIT), + sinSPhi(rhs.sinSPhi), cosSPhi(rhs.cosSPhi), + sinEPhi(rhs.sinEPhi), cosEPhi(rhs.cosEPhi), fPhiFullTube(rhs.fPhiFullTube), + halfCarTolerance(rhs.halfCarTolerance), + halfRadTolerance(rhs.halfRadTolerance), + halfAngTolerance(rhs.halfAngTolerance) +{ +} + +////////////////////////////////////////////////////////////////////////// +// +// Assignment operator + +G4Tubs& G4Tubs::operator = (const G4Tubs& rhs) +{ + // Check assignment to self + // + if (this == &rhs) { return *this; } + + // Copy base class data + // + G4CSGSolid::operator=(rhs); + + // Copy data + // + kRadTolerance = rhs.kRadTolerance; kAngTolerance = rhs.kAngTolerance; + fRMin = rhs.fRMin; fRMax = rhs.fRMax; fDz = rhs.fDz; + fSPhi = rhs.fSPhi; fDPhi = rhs.fDPhi; + sinCPhi = rhs.sinCPhi; cosCPhi = rhs.cosCPhi; + cosHDPhiOT = rhs.cosHDPhiOT; cosHDPhiIT = rhs.cosHDPhiIT; + sinSPhi = rhs.sinSPhi; cosSPhi = rhs.cosSPhi; + sinEPhi = rhs.sinEPhi; cosEPhi = rhs.cosEPhi; + fPhiFullTube = rhs.fPhiFullTube; + halfCarTolerance = rhs.halfCarTolerance; + halfRadTolerance = rhs.halfRadTolerance; + halfAngTolerance = rhs.halfAngTolerance; + + return *this; +} + +///////////////////////////////////////////////////////////////////////// +// +// Dispatch to parameterisation for replication mechanism dimension +// computation & modification. + +void G4Tubs::ComputeDimensions( G4VPVParameterisation* p, + const G4int n, + const G4VPhysicalVolume* pRep ) +{ + p->ComputeDimensions(*this,n,pRep) ; +} + +///////////////////////////////////////////////////////////////////////// +// +// Get bounding box + +void G4Tubs::BoundingLimits(G4ThreeVector& pMin, G4ThreeVector& pMax) const +{ + G4double rmin = GetInnerRadius(); + G4double rmax = GetOuterRadius(); + G4double dz = GetZHalfLength(); + + // Find bounding box + // + if (GetDeltaPhiAngle() < twopi) + { + G4TwoVector vmin,vmax; + G4GeomTools::DiskExtent(rmin,rmax, + GetSinStartPhi(),GetCosStartPhi(), + GetSinEndPhi(),GetCosEndPhi(), + vmin,vmax); + pMin.set(vmin.x(),vmin.y(),-dz); + pMax.set(vmax.x(),vmax.y(), dz); + } + else + { + pMin.set(-rmax,-rmax,-dz); + pMax.set( rmax, rmax, dz); + } + + // Check correctness of the bounding box + // + if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z()) + { + std::ostringstream message; + message << "Bad bounding box (min >= max) for solid: " + << GetName() << " !" + << "\npMin = " << pMin + << "\npMax = " << pMax; + G4Exception("G4Tubs::BoundingLimits()", "GeomMgt0001", + JustWarning, message); + DumpInfo(); + } +} + +///////////////////////////////////////////////////////////////////////// +// +// Calculate extent under transform and specified limit + +G4bool G4Tubs::CalculateExtent( const EAxis pAxis, + const G4VoxelLimits& pVoxelLimit, + const G4AffineTransform& pTransform, + G4double& pMin, + G4double& pMax ) const +{ + G4ThreeVector bmin, bmax; + G4bool exist; + + // Get bounding box + BoundingLimits(bmin,bmax); + + // Check bounding box + G4BoundingEnvelope bbox(bmin,bmax); +#ifdef G4BBOX_EXTENT + if (true) return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax); +#endif + if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax)) + { + return exist = (pMin < pMax) ? true : false; + } + + // Get parameters of the solid + G4double rmin = GetInnerRadius(); + G4double rmax = GetOuterRadius(); + G4double dz = GetZHalfLength(); + G4double dphi = GetDeltaPhiAngle(); + + // Find bounding envelope and calculate extent + // + const G4int NSTEPS = 24; // number of steps for whole circle + G4double astep = twopi/NSTEPS; // max angle for one step + G4int ksteps = (dphi <= astep) ? 1 : (G4int)((dphi-deg)/astep) + 1; + G4double ang = dphi/ksteps; + + G4double sinHalf = std::sin(0.5*ang); + G4double cosHalf = std::cos(0.5*ang); + G4double sinStep = 2.*sinHalf*cosHalf; + G4double cosStep = 1. - 2.*sinHalf*sinHalf; + G4double rext = rmax/cosHalf; + + // bounding envelope for full cylinder consists of two polygons, + // in other cases it is a sequence of quadrilaterals + if (rmin == 0 && dphi == twopi) + { + G4double sinCur = sinHalf; + G4double cosCur = cosHalf; + + G4ThreeVectorList baseA(NSTEPS),baseB(NSTEPS); + for (G4int k=0; k polygons(2); + polygons[0] = &baseA; + polygons[1] = &baseB; + G4BoundingEnvelope benv(bmin,bmax,polygons); + exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax); + } + else + { + G4double sinStart = GetSinStartPhi(); + G4double cosStart = GetCosStartPhi(); + G4double sinEnd = GetSinEndPhi(); + G4double cosEnd = GetCosEndPhi(); + G4double sinCur = sinStart*cosHalf + cosStart*sinHalf; + G4double cosCur = cosStart*cosHalf - sinStart*sinHalf; + + // set quadrilaterals + G4ThreeVectorList pols[NSTEPS+2]; + for (G4int k=0; k polygons; + polygons.resize(ksteps+2); + for (G4int k=0; k= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax)) + { + if ( fPhiFullTube ) + { + in = kInside ; + } + else + { + // Try inner tolerant phi boundaries (=>inside) + // if not inside, try outer tolerant phi boundaries + + if ( (tolRMin==0) && (std::fabs(p.x())<=halfCarTolerance) + && (std::fabs(p.y())<=halfCarTolerance) ) + { + in=kSurface; + } + else + { + pPhi = std::atan2(p.y(),p.x()) ; + if ( pPhi < -halfAngTolerance ) { pPhi += twopi; } // 0<=pPhi<2pi + + if ( fSPhi >= 0 ) + { + if ( (std::fabs(pPhi) < halfAngTolerance) + && (std::fabs(fSPhi + fDPhi - twopi) < halfAngTolerance) ) + { + pPhi += twopi ; // 0 <= pPhi < 2pi + } + if ( (pPhi >= fSPhi + halfAngTolerance) + && (pPhi <= fSPhi + fDPhi - halfAngTolerance) ) + { + in = kInside ; + } + else if ( (pPhi >= fSPhi - halfAngTolerance) + && (pPhi <= fSPhi + fDPhi + halfAngTolerance) ) + { + in = kSurface ; + } + } + else // fSPhi < 0 + { + if ( (pPhi <= fSPhi + twopi - halfAngTolerance) + && (pPhi >= fSPhi + fDPhi + halfAngTolerance) ) {;} //kOutside + else if ( (pPhi <= fSPhi + twopi + halfAngTolerance) + && (pPhi >= fSPhi + fDPhi - halfAngTolerance) ) + { + in = kSurface ; + } + else + { + in = kInside ; + } + } + } + } + } + else // Try generous boundaries + { + tolRMin = fRMin - halfRadTolerance ; + tolRMax = fRMax + halfRadTolerance ; + + if ( tolRMin < 0 ) { tolRMin = 0; } + + if ( (r2 >= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax) ) + { + if (fPhiFullTube || (r2 <=halfRadTolerance*halfRadTolerance) ) + { // Continuous in phi or on z-axis + in = kSurface ; + } + else // Try outer tolerant phi boundaries only + { + pPhi = std::atan2(p.y(),p.x()) ; + + if ( pPhi < -halfAngTolerance) { pPhi += twopi; } // 0<=pPhi<2pi + if ( fSPhi >= 0 ) + { + if ( (std::fabs(pPhi) < halfAngTolerance) + && (std::fabs(fSPhi + fDPhi - twopi) < halfAngTolerance) ) + { + pPhi += twopi ; // 0 <= pPhi < 2pi + } + if ( (pPhi >= fSPhi - halfAngTolerance) + && (pPhi <= fSPhi + fDPhi + halfAngTolerance) ) + { + in = kSurface ; + } + } + else // fSPhi < 0 + { + if ( (pPhi <= fSPhi + twopi - halfAngTolerance) + && (pPhi >= fSPhi + fDPhi + halfAngTolerance) ) {;} // kOutside + else + { + in = kSurface ; + } + } + } + } + } + } + else if (std::fabs(p.z()) <= fDz + halfCarTolerance) + { // Check within tolerant r limits + r2 = p.x()*p.x() + p.y()*p.y() ; + tolRMin = fRMin - halfRadTolerance ; + tolRMax = fRMax + halfRadTolerance ; + + if ( tolRMin < 0 ) { tolRMin = 0; } + + if ( (r2 >= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax) ) + { + if (fPhiFullTube || (r2 <=halfRadTolerance*halfRadTolerance)) + { // Continuous in phi or on z-axis + in = kSurface ; + } + else // Try outer tolerant phi boundaries + { + pPhi = std::atan2(p.y(),p.x()) ; + + if ( pPhi < -halfAngTolerance ) { pPhi += twopi; } // 0<=pPhi<2pi + if ( fSPhi >= 0 ) + { + if ( (std::fabs(pPhi) < halfAngTolerance) + && (std::fabs(fSPhi + fDPhi - twopi) < halfAngTolerance) ) + { + pPhi += twopi ; // 0 <= pPhi < 2pi + } + if ( (pPhi >= fSPhi - halfAngTolerance) + && (pPhi <= fSPhi + fDPhi + halfAngTolerance) ) + { + in = kSurface; + } + } + else // fSPhi < 0 + { + if ( (pPhi <= fSPhi + twopi - halfAngTolerance) + && (pPhi >= fSPhi + fDPhi + halfAngTolerance) ) {;} + else + { + in = kSurface ; + } + } + } + } + } + return in; +} + +/////////////////////////////////////////////////////////////////////////// +// +// Return unit normal of surface closest to p +// - note if point on z axis, ignore phi divided sides +// - unsafe if point close to z axis a rmin=0 - no explicit checks + +G4ThreeVector G4Tubs::SurfaceNormal( const G4ThreeVector& p ) const +{ + G4int noSurfaces = 0; + G4double rho, pPhi; + G4double distZ, distRMin, distRMax; + G4double distSPhi = kInfinity, distEPhi = kInfinity; + + G4ThreeVector norm, sumnorm(0.,0.,0.); + G4ThreeVector nZ = G4ThreeVector(0, 0, 1.0); + G4ThreeVector nR, nPs, nPe; + + rho = std::sqrt(p.x()*p.x() + p.y()*p.y()); + + distRMin = std::fabs(rho - fRMin); + distRMax = std::fabs(rho - fRMax); + distZ = std::fabs(std::fabs(p.z()) - fDz); + + if (!fPhiFullTube) // Protected against (0,0,z) + { + if ( rho > halfCarTolerance ) + { + pPhi = std::atan2(p.y(),p.x()); + + if(pPhi < fSPhi- halfCarTolerance) { pPhi += twopi; } + else if(pPhi > fSPhi+fDPhi+ halfCarTolerance) { pPhi -= twopi; } + + distSPhi = std::fabs(pPhi - fSPhi); + distEPhi = std::fabs(pPhi - fSPhi - fDPhi); + } + else if( !fRMin ) + { + distSPhi = 0.; + distEPhi = 0.; + } + nPs = G4ThreeVector(std::sin(fSPhi),-std::cos(fSPhi),0); + nPe = G4ThreeVector(-std::sin(fSPhi+fDPhi),std::cos(fSPhi+fDPhi),0); + } + if ( rho > halfCarTolerance ) { nR = G4ThreeVector(p.x()/rho,p.y()/rho,0); } + + if( distRMax <= halfCarTolerance ) + { + noSurfaces ++; + sumnorm += nR; + } + if( fRMin && (distRMin <= halfCarTolerance) ) + { + noSurfaces ++; + sumnorm -= nR; + } + if( fDPhi < twopi ) + { + if (distSPhi <= halfAngTolerance) + { + noSurfaces ++; + sumnorm += nPs; + } + if (distEPhi <= halfAngTolerance) + { + noSurfaces ++; + sumnorm += nPe; + } + } + if (distZ <= halfCarTolerance) + { + noSurfaces ++; + if ( p.z() >= 0.) { sumnorm += nZ; } + else { sumnorm -= nZ; } + } + if ( noSurfaces == 0 ) + { +#ifdef G4CSGDEBUG + G4Exception("G4Tubs::SurfaceNormal(p)", "GeomSolids1002", + JustWarning, "Point p is not on surface !?" ); + G4int oldprc = G4cout.precision(20); + G4cout<< "G4Tubs::SN ( "< 0 ) { norm = G4ThreeVector(0,0,1) ; } + else { norm = G4ThreeVector(0,0,-1); } + break ; + } + case kNSPhi: + { + norm = G4ThreeVector(std::sin(fSPhi), -std::cos(fSPhi), 0) ; + break ; + } + case kNEPhi: + { + norm = G4ThreeVector(-std::sin(fSPhi+fDPhi), std::cos(fSPhi+fDPhi), 0) ; + break; + } + default: // Should never reach this case ... + { + DumpInfo(); + G4Exception("G4Tubs::ApproxSurfaceNormal()", + "GeomSolids1002", JustWarning, + "Undefined side for valid surface normal to solid."); + break ; + } + } + return norm; +} + +//////////////////////////////////////////////////////////////////// +// +// +// Calculate distance to shape from outside, along normalised vector +// - return kInfinity if no intersection, or intersection distance <= tolerance +// +// - Compute the intersection with the z planes +// - if at valid r, phi, return +// +// -> If point is outer outer radius, compute intersection with rmax +// - if at valid phi,z return +// +// -> Compute intersection with inner radius, taking largest +ve root +// - if valid (in z,phi), save intersction +// +// -> If phi segmented, compute intersections with phi half planes +// - return smallest of valid phi intersections and +// inner radius intersection +// +// NOTE: +// - 'if valid' implies tolerant checking of intersection points + +G4double G4Tubs::DistanceToIn( const G4ThreeVector& p, + const G4ThreeVector& v ) const +{ + G4double snxt = kInfinity ; // snxt = default return value + G4double tolORMin2, tolIRMax2 ; // 'generous' radii squared + G4double tolORMax2, tolIRMin2, tolODz, tolIDz ; + const G4double dRmax = 100.*fRMax; + + // Intersection point variables + // + G4double Dist, sd, xi, yi, zi, rho2, inum, iden, cosPsi, Comp ; + G4double t1, t2, t3, b, c, d ; // Quadratic solver variables + + // Calculate tolerant rmin and rmax + + if (fRMin > kRadTolerance) + { + tolORMin2 = (fRMin - halfRadTolerance)*(fRMin - halfRadTolerance) ; + tolIRMin2 = (fRMin + halfRadTolerance)*(fRMin + halfRadTolerance) ; + } + else + { + tolORMin2 = 0.0 ; + tolIRMin2 = 0.0 ; + } + tolORMax2 = (fRMax + halfRadTolerance)*(fRMax + halfRadTolerance) ; + tolIRMax2 = (fRMax - halfRadTolerance)*(fRMax - halfRadTolerance) ; + + // Intersection with Z surfaces + + tolIDz = fDz - halfCarTolerance ; + tolODz = fDz + halfCarTolerance ; + + if (std::fabs(p.z()) >= tolIDz) + { + if ( p.z()*v.z() < 0 ) // at +Z going in -Z or visa versa + { + sd = (std::fabs(p.z()) - fDz)/std::fabs(v.z()) ; // Z intersect distance + + if(sd < 0.0) { sd = 0.0; } + + xi = p.x() + sd*v.x() ; // Intersection coords + yi = p.y() + sd*v.y() ; + rho2 = xi*xi + yi*yi ; + + // Check validity of intersection + + if ((tolIRMin2 <= rho2) && (rho2 <= tolIRMax2)) + { + if (!fPhiFullTube && rho2) + { + // Psi = angle made with central (average) phi of shape + // + inum = xi*cosCPhi + yi*sinCPhi ; + iden = std::sqrt(rho2) ; + cosPsi = inum/iden ; + if (cosPsi >= cosHDPhiIT) { return sd ; } + } + else + { + return sd ; + } + } + } + else + { + if ( snxt cannot intersect + } + } + + // -> Can not intersect z surfaces + // + // Intersection with rmax (possible return) and rmin (must also check phi) + // + // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc. + // + // Intersects with x^2+y^2=R^2 + // + // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0 + // t1 t2 t3 + + t1 = 1.0 - v.z()*v.z() ; + t2 = p.x()*v.x() + p.y()*v.y() ; + t3 = p.x()*p.x() + p.y()*p.y() ; + + if ( t1 > 0 ) // Check not || to z axis + { + b = t2/t1 ; + c = t3 - fRMax*fRMax ; + if ((t3 >= tolORMax2) && (t2<0)) // This also handles the tangent case + { + // Try outer cylinder intersection + // c=(t3-fRMax*fRMax)/t1; + + c /= t1 ; + d = b*b - c ; + + if (d >= 0) // If real root + { + sd = c/(-b+std::sqrt(d)); + if (sd >= 0) // If 'forwards' + { + if ( sd>dRmax ) // Avoid rounding errors due to precision issues on + { // 64 bits systems. Split long distances and recompute + G4double fTerm = sd-std::fmod(sd,dRmax); + sd = fTerm + DistanceToIn(p+fTerm*v,v); + } + // Check z intersection + // + zi = p.z() + sd*v.z() ; + if (std::fabs(zi)<=tolODz) + { + // Z ok. Check phi intersection if reqd + // + if (fPhiFullTube) + { + return sd ; + } + else + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMax ; + if (cosPsi >= cosHDPhiIT) { return sd ; } + } + } // end if std::fabs(zi) + } // end if (sd>=0) + } // end if (d>=0) + } // end if (r>=fRMax) + else + { + // Inside outer radius : + // check not inside, and heading through tubs (-> 0 to in) + + if ((t3 > tolIRMin2) && (t2 < 0) && (std::fabs(p.z()) <= tolIDz)) + { + // Inside both radii, delta r -ve, inside z extent + + if (!fPhiFullTube) + { + inum = p.x()*cosCPhi + p.y()*sinCPhi ; + iden = std::sqrt(t3) ; + cosPsi = inum/iden ; + if (cosPsi >= cosHDPhiIT) + { + // In the old version, the small negative tangent for the point + // on surface was not taken in account, and returning 0.0 ... + // New version: check the tangent for the point on surface and + // if no intersection, return kInfinity, if intersection instead + // return sd. + // + c = t3-fRMax*fRMax; + if ( c<=0.0 ) + { + return 0.0; + } + else + { + c = c/t1 ; + d = b*b-c; + if ( d>=0.0 ) + { + snxt = c/(-b+std::sqrt(d)); // using safe solution + // for quadratic equation + if ( snxt < halfCarTolerance ) { snxt=0; } + return snxt ; + } + else + { + return kInfinity; + } + } + } + } + else + { + // In the old version, the small negative tangent for the point + // on surface was not taken in account, and returning 0.0 ... + // New version: check the tangent for the point on surface and + // if no intersection, return kInfinity, if intersection instead + // return sd. + // + c = t3 - fRMax*fRMax; + if ( c<=0.0 ) + { + return 0.0; + } + else + { + c = c/t1 ; + d = b*b-c; + if ( d>=0.0 ) + { + snxt= c/(-b+std::sqrt(d)); // using safe solution + // for quadratic equation + if ( snxt < halfCarTolerance ) { snxt=0; } + return snxt ; + } + else + { + return kInfinity; + } + } + } // end if (!fPhiFullTube) + } // end if (t3>tolIRMin2) + } // end if (Inside Outer Radius) + if ( fRMin ) // Try inner cylinder intersection + { + c = (t3 - fRMin*fRMin)/t1 ; + d = b*b - c ; + if ( d >= 0.0 ) // If real root + { + // Always want 2nd root - we are outside and know rmax Hit was bad + // - If on surface of rmin also need farthest root + + sd =( b > 0. )? c/(-b - std::sqrt(d)) : (-b + std::sqrt(d)); + if (sd >= -halfCarTolerance) // check forwards + { + // Check z intersection + // + if(sd < 0.0) { sd = 0.0; } + if ( sd>dRmax ) // Avoid rounding errors due to precision issues seen + { // 64 bits systems. Split long distances and recompute + G4double fTerm = sd-std::fmod(sd,dRmax); + sd = fTerm + DistanceToIn(p+fTerm*v,v); + } + zi = p.z() + sd*v.z() ; + if (std::fabs(zi) <= tolODz) + { + // Z ok. Check phi + // + if ( fPhiFullTube ) + { + return sd ; + } + else + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMin ; + if (cosPsi >= cosHDPhiIT) + { + // Good inner radius isect + // - but earlier phi isect still possible + + snxt = sd ; + } + } + } // end if std::fabs(zi) + } // end if (sd>=0) + } // end if (d>=0) + } // end if (fRMin) + } + + // Phi segment intersection + // + // o Tolerant of points inside phi planes by up to kCarTolerance*0.5 + // + // o NOTE: Large duplication of code between sphi & ephi checks + // -> only diffs: sphi -> ephi, Comp -> -Comp and half-plane + // intersection check <=0 -> >=0 + // -> use some form of loop Construct ? + // + if ( !fPhiFullTube ) + { + // First phi surface (Starting phi) + // + Comp = v.x()*sinSPhi - v.y()*cosSPhi ; + + if ( Comp < 0 ) // Component in outwards normal dirn + { + Dist = (p.y()*cosSPhi - p.x()*sinSPhi) ; + + if ( Dist < halfCarTolerance ) + { + sd = Dist/Comp ; + + if (sd < snxt) + { + if ( sd < 0 ) { sd = 0.0; } + zi = p.z() + sd*v.z() ; + if ( std::fabs(zi) <= tolODz ) + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + rho2 = xi*xi + yi*yi ; + + if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) ) + || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2) + && ( v.y()*cosSPhi - v.x()*sinSPhi > 0 ) + && ( v.x()*cosSPhi + v.y()*sinSPhi >= 0 ) ) + || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2) + && (v.y()*cosSPhi - v.x()*sinSPhi > 0) + && (v.x()*cosSPhi + v.y()*sinSPhi < 0) ) ) + { + // z and r intersections good + // - check intersecting with correct half-plane + // + if ((yi*cosCPhi-xi*sinCPhi) <= halfCarTolerance) { snxt = sd; } + } + } + } + } + } + + // Second phi surface (Ending phi) + + Comp = -(v.x()*sinEPhi - v.y()*cosEPhi) ; + + if (Comp < 0 ) // Component in outwards normal dirn + { + Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) ; + + if ( Dist < halfCarTolerance ) + { + sd = Dist/Comp ; + + if (sd < snxt) + { + if ( sd < 0 ) { sd = 0; } + zi = p.z() + sd*v.z() ; + if ( std::fabs(zi) <= tolODz ) + { + xi = p.x() + sd*v.x() ; + yi = p.y() + sd*v.y() ; + rho2 = xi*xi + yi*yi ; + if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) ) + || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2) + && (v.x()*sinEPhi - v.y()*cosEPhi > 0) + && (v.x()*cosEPhi + v.y()*sinEPhi >= 0) ) + || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2) + && (v.x()*sinEPhi - v.y()*cosEPhi > 0) + && (v.x()*cosEPhi + v.y()*sinEPhi < 0) ) ) + { + // z and r intersections good + // - check intersecting with correct half-plane + // + if ( (yi*cosCPhi-xi*sinCPhi) >= 0 ) { snxt = sd; } + } //?? >=-halfCarTolerance + } + } + } + } // Comp < 0 + } // !fPhiFullTube + if ( snxt If point is outer outer radius, compute intersection with rmax +// - if at valid phi,z return +// +// -> Compute intersection with inner radius, taking largest +ve root +// - if valid (in z,phi), save intersction +// +// -> If phi segmented, compute intersections with phi half planes +// - return smallest of valid phi intersections and +// inner radius intersection +// +// NOTE: +// - Precalculations for phi trigonometry are Done `just in time' +// - `if valid' implies tolerant checking of intersection points +// Calculate distance (<= actual) to closest surface of shape from outside +// - Calculate distance to z, radial planes +// - Only to phi planes if outside phi extent +// - Return 0 if point inside + +G4double G4Tubs::DistanceToIn( const G4ThreeVector& p ) const +{ + G4double safe=0.0, rho, safe1, safe2, safe3 ; + G4double safePhi, cosPsi ; + + rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; + safe1 = fRMin - rho ; + safe2 = rho - fRMax ; + safe3 = std::fabs(p.z()) - fDz ; + + if ( safe1 > safe2 ) { safe = safe1; } + else { safe = safe2; } + if ( safe3 > safe ) { safe = safe3; } + + if ( (!fPhiFullTube) && (rho) ) + { + // Psi=angle from central phi to point + // + cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/rho ; + + if ( cosPsi < std::cos(fDPhi*0.5) ) + { + // Point lies outside phi range + + if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 0 ) + { + safePhi = std::fabs(p.x()*sinSPhi - p.y()*cosSPhi) ; + } + else + { + safePhi = std::fabs(p.x()*sinEPhi - p.y()*cosEPhi) ; + } + if ( safePhi > safe ) { safe = safePhi; } + } + } + if ( safe < 0 ) { safe = 0; } + return safe ; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Calculate distance to surface of shape from `inside', allowing for tolerance +// - Only Calc rmax intersection if no valid rmin intersection + +G4double G4Tubs::DistanceToOut( const G4ThreeVector& p, + const G4ThreeVector& v, + const G4bool calcNorm, + G4bool *validNorm, + G4ThreeVector *n ) const +{ + ESide side=kNull , sider=kNull, sidephi=kNull ; + G4double snxt, srd=kInfinity, sphi=kInfinity, pdist ; + G4double deltaR, t1, t2, t3, b, c, d2, roMin2 ; + + // Vars for phi intersection: + + G4double pDistS, compS, pDistE, compE, sphi2, xi, yi, vphi, roi2 ; + + // Z plane intersection + + if (v.z() > 0 ) + { + pdist = fDz - p.z() ; + if ( pdist > halfCarTolerance ) + { + snxt = pdist/v.z() ; + side = kPZ ; + } + else + { + if (calcNorm) + { + *n = G4ThreeVector(0,0,1) ; + *validNorm = true ; + } + return snxt = 0 ; + } + } + else if ( v.z() < 0 ) + { + pdist = fDz + p.z() ; + + if ( pdist > halfCarTolerance ) + { + snxt = -pdist/v.z() ; + side = kMZ ; + } + else + { + if (calcNorm) + { + *n = G4ThreeVector(0,0,-1) ; + *validNorm = true ; + } + return snxt = 0.0 ; + } + } + else + { + snxt = kInfinity ; // Travel perpendicular to z axis + side = kNull; + } + + // Radial Intersections + // + // Find intersection with cylinders at rmax/rmin + // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc. + // + // Intersects with x^2+y^2=R^2 + // + // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0 + // + // t1 t2 t3 + + t1 = 1.0 - v.z()*v.z() ; // since v normalised + t2 = p.x()*v.x() + p.y()*v.y() ; + t3 = p.x()*p.x() + p.y()*p.y() ; + + if ( snxt > 10*(fDz+fRMax) ) { roi2 = 2*fRMax*fRMax; } + else { roi2 = snxt*snxt*t1 + 2*snxt*t2 + t3; } // radius^2 on +-fDz + + if ( t1 > 0 ) // Check not parallel + { + // Calculate srd, r exit distance + + if ( (t2 >= 0.0) && (roi2 > fRMax*(fRMax + kRadTolerance)) ) + { + // Delta r not negative => leaving via rmax + + deltaR = t3 - fRMax*fRMax ; + + // NOTE: Should use rho-fRMax<-kRadTolerance*0.5 + // - avoid sqrt for efficiency + + if ( deltaR < -kRadTolerance*fRMax ) + { + b = t2/t1 ; + c = deltaR/t1 ; + d2 = b*b-c; + if( d2 >= 0 ) { srd = c/( -b - std::sqrt(d2)); } + else { srd = 0.; } + sider = kRMax ; + } + else + { + // On tolerant boundary & heading outwards (or perpendicular to) + // outer radial surface -> leaving immediately + + if ( calcNorm ) + { + *n = G4ThreeVector(p.x(), p.y(), 0) ; + n->setMag(1) ; + *validNorm = true ; + } + return snxt = 0 ; // Leaving by rmax immediately + } + } + else if ( t2 < 0. ) // i.e. t2 < 0; Possible rmin intersection + { + roMin2 = t3 - t2*t2/t1 ; // min ro2 of the plane of movement + + if ( fRMin && (roMin2 < fRMin*(fRMin - kRadTolerance)) ) + { + deltaR = t3 - fRMin*fRMin ; + b = t2/t1 ; + c = deltaR/t1 ; + d2 = b*b - c ; + + if ( d2 >= 0 ) // Leaving via rmin + { + // NOTE: SHould use rho-rmin>kRadTolerance*0.5 + // - avoid sqrt for efficiency + + if (deltaR > kRadTolerance*fRMin) + { + srd = c/(-b+std::sqrt(d2)); + sider = kRMin ; + } + else + { + if ( calcNorm ) { *validNorm = false; } // Concave side + return snxt = 0.0; + } + } + else // No rmin intersect -> must be rmax intersect + { + deltaR = t3 - fRMax*fRMax ; + c = deltaR/t1 ; + d2 = b*b-c; + if( d2 >=0. ) + { + srd = -b + std::sqrt(d2) ; + sider = kRMax ; + } + else // Case: On the border+t2setMag(1) ; + *validNorm = true ; + } + return snxt = 0.0; + } + } + } + else if ( roi2 > fRMax*(fRMax + kRadTolerance) ) + // No rmin intersect -> must be rmax intersect + { + deltaR = t3 - fRMax*fRMax ; + b = t2/t1 ; + c = deltaR/t1; + d2 = b*b-c; + if( d2 >= 0 ) + { + srd = -b + std::sqrt(d2) ; + sider = kRMax ; + } + else // Case: On the border+t2setMag(1) ; + *validNorm = true ; + } + return snxt = 0.0; + } + } + } + + // Phi Intersection + + if ( !fPhiFullTube ) + { + // add angle calculation with correction + // of the difference in domain of atan2 and Sphi + // + vphi = std::atan2(v.y(),v.x()) ; + + if ( vphi < fSPhi - halfAngTolerance ) { vphi += twopi; } + else if ( vphi > fSPhi + fDPhi + halfAngTolerance ) { vphi -= twopi; } + + + if ( p.x() || p.y() ) // Check if on z axis (rho not needed later) + { + // pDist -ve when inside + + pDistS = p.x()*sinSPhi - p.y()*cosSPhi ; + pDistE = -p.x()*sinEPhi + p.y()*cosEPhi ; + + // Comp -ve when in direction of outwards normal + + compS = -sinSPhi*v.x() + cosSPhi*v.y() ; + compE = sinEPhi*v.x() - cosEPhi*v.y() ; + + sidephi = kNull; + + if( ( (fDPhi <= pi) && ( (pDistS <= halfCarTolerance) + && (pDistE <= halfCarTolerance) ) ) + || ( (fDPhi > pi) && !((pDistS > halfCarTolerance) + && (pDistE > halfCarTolerance) ) ) ) + { + // Inside both phi *full* planes + + if ( compS < 0 ) + { + sphi = pDistS/compS ; + + if (sphi >= -halfCarTolerance) + { + xi = p.x() + sphi*v.x() ; + yi = p.y() + sphi*v.y() ; + + // Check intersecting with correct half-plane + // (if not -> no intersect) + // + if((std::fabs(xi)<=kCarTolerance)&&(std::fabs(yi)<=kCarTolerance)) + { + sidephi = kSPhi; + if (((fSPhi-halfAngTolerance)<=vphi) + &&((fSPhi+fDPhi+halfAngTolerance)>=vphi)) + { + sphi = kInfinity; + } + } + else if ( yi*cosCPhi-xi*sinCPhi >=0 ) + { + sphi = kInfinity ; + } + else + { + sidephi = kSPhi ; + if ( pDistS > -halfCarTolerance ) + { + sphi = 0.0 ; // Leave by sphi immediately + } + } + } + else + { + sphi = kInfinity ; + } + } + else + { + sphi = kInfinity ; + } + + if ( compE < 0 ) + { + sphi2 = pDistE/compE ; + + // Only check further if < starting phi intersection + // + if ( (sphi2 > -halfCarTolerance) && (sphi2 < sphi) ) + { + xi = p.x() + sphi2*v.x() ; + yi = p.y() + sphi2*v.y() ; + + if((std::fabs(xi)<=kCarTolerance)&&(std::fabs(yi)<=kCarTolerance)) + { + // Leaving via ending phi + // + if( !((fSPhi-halfAngTolerance <= vphi) + &&(fSPhi+fDPhi+halfAngTolerance >= vphi)) ) + { + sidephi = kEPhi ; + if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; } + else { sphi = 0.0 ; } + } + } + else // Check intersecting with correct half-plane + + if ( (yi*cosCPhi-xi*sinCPhi) >= 0) + { + // Leaving via ending phi + // + sidephi = kEPhi ; + if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; } + else { sphi = 0.0 ; } + } + } + } + } + else + { + sphi = kInfinity ; + } + } + else + { + // On z axis + travel not || to z axis -> if phi of vector direction + // within phi of shape, Step limited by rmax, else Step =0 + + if ( (fSPhi - halfAngTolerance <= vphi) + && (vphi <= fSPhi + fDPhi + halfAngTolerance ) ) + { + sphi = kInfinity ; + } + else + { + sidephi = kSPhi ; // arbitrary + sphi = 0.0 ; + } + } + if (sphi < snxt) // Order intersecttions + { + snxt = sphi ; + side = sidephi ; + } + } + if (srd < snxt) // Order intersections + { + snxt = srd ; + side = sider ; + } + } + if (calcNorm) + { + switch(side) + { + case kRMax: + // Note: returned vector not normalised + // (divide by fRMax for unit vector) + // + xi = p.x() + snxt*v.x() ; + yi = p.y() + snxt*v.y() ; + *n = G4ThreeVector(xi, yi, 0) ; + n->setMag(1) ; + *validNorm = true ; + break ; + + case kRMin: + *validNorm = false ; // Rmin is inconvex + break ; + + case kSPhi: + if ( fDPhi <= pi ) + { + *n = G4ThreeVector(sinSPhi,-cosSPhi,0) ; + n->setMag(1) ; + *validNorm = true ; + } + else + { + *validNorm = false ; + } + break ; + + case kEPhi: + if (fDPhi <= pi) + { + *n = G4ThreeVector(-sinEPhi,cosEPhi,0) ; + n->setMag(1) ; + *validNorm = true ; + } + else + { + *validNorm = false ; + } + break ; + + case kPZ: + *n = G4ThreeVector(0,0,1) ; + *validNorm = true ; + break ; + + case kMZ: + *n = G4ThreeVector(0,0,-1) ; + *validNorm = true ; + break ; + + default: + G4cout << G4endl ; + DumpInfo(); + std::ostringstream message; + G4int oldprc = message.precision(16); + message << "Undefined side for valid surface normal to solid." + << G4endl + << "Position:" << G4endl << G4endl + << "p.x() = " << p.x()/mm << " mm" << G4endl + << "p.y() = " << p.y()/mm << " mm" << G4endl + << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl + << "Direction:" << G4endl << G4endl + << "v.x() = " << v.x() << G4endl + << "v.y() = " << v.y() << G4endl + << "v.z() = " << v.z() << G4endl << G4endl + << "Proposed distance :" << G4endl << G4endl + << "snxt = " << snxt/mm << " mm" << G4endl ; + message.precision(oldprc) ; + G4Exception("G4Tubs::DistanceToOut(p,v,..)", "GeomSolids1002", + JustWarning, message); + break ; + } + } + if ( snxt=0) && (chose < aOne) ) + { + xRand = fRMax*cosphi; + yRand = fRMax*sinphi; + zRand = G4RandFlat::shoot(-1.*fDz,fDz); + return G4ThreeVector (xRand, yRand, zRand); + } + else if( (chose >= aOne) && (chose < aOne + aTwo) ) + { + xRand = fRMin*cosphi; + yRand = fRMin*sinphi; + zRand = G4RandFlat::shoot(-1.*fDz,fDz); + return G4ThreeVector (xRand, yRand, zRand); + } + else if( (chose >= aOne + aTwo) && (chose < aOne + aTwo + aThr) ) + { + xRand = rRand*cosphi; + yRand = rRand*sinphi; + zRand = fDz; + return G4ThreeVector (xRand, yRand, zRand); + } + else if( (chose >= aOne + aTwo + aThr) && (chose < aOne + aTwo + 2.*aThr) ) + { + xRand = rRand*cosphi; + yRand = rRand*sinphi; + zRand = -1.*fDz; + return G4ThreeVector (xRand, yRand, zRand); + } + else if( (chose >= aOne + aTwo + 2.*aThr) + && (chose < aOne + aTwo + 2.*aThr + aFou) ) + { + xRand = rRand*std::cos(fSPhi); + yRand = rRand*std::sin(fSPhi); + zRand = G4RandFlat::shoot(-1.*fDz,fDz); + return G4ThreeVector (xRand, yRand, zRand); + } + else + { + xRand = rRand*std::cos(fSPhi+fDPhi); + yRand = rRand*std::sin(fSPhi+fDPhi); + zRand = G4RandFlat::shoot(-1.*fDz,fDz); + return G4ThreeVector (xRand, yRand, zRand); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// Methods for visualisation + +void G4Tubs::DescribeYourselfTo ( G4VGraphicsScene& scene ) const +{ + scene.AddSolid (*this) ; +} + +G4Polyhedron* G4Tubs::CreatePolyhedron () const +{ + return new G4PolyhedronTubs (fRMin, fRMax, fDz, fSPhi, fDPhi) ; +} +#endif diff --git a/src/G4.10.04.p02fixes/G4VDivisionParameterisation.cc b/src/G4.10.04.p02fixes/G4VDivisionParameterisation.cc new file mode 100644 index 0000000..a9c6e09 --- /dev/null +++ b/src/G4.10.04.p02fixes/G4VDivisionParameterisation.cc @@ -0,0 +1,214 @@ +// +// ******************************************************************** +// * 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: G4VDivisionParameterisation.cc 92625 2015-09-09 12:34:07Z gcosmo $ +// +// class G4VDivisionParameterisation Implementation file +// +// 26.05.03 - P.Arce, Initial version +// 08.04.04 - I.Hrivnacova, Implemented reflection +// 21.04.10 - M.Asai, Added gaps +// -------------------------------------------------------------------- + +#include "G4VDivisionParameterisation.hh" +#include "G4VSolid.hh" +#include "G4VPhysicalVolume.hh" +#include "G4RotationMatrix.hh" +#include "G4ReflectedSolid.hh" +#include "G4GeometryTolerance.hh" +#include "G4AutoDelete.hh" +#include "G4AutoLock.hh" + +const G4int G4VDivisionParameterisation::verbose = 5; +G4ThreadLocal G4RotationMatrix* G4VDivisionParameterisation::fRot = 0; + +//-------------------------------------------------------------------------- +G4VDivisionParameterisation:: +G4VDivisionParameterisation( EAxis axis, G4int nDiv, + G4double step, G4double offset, + DivisionType divType, G4VSolid* motherSolid ) + : faxis(axis), fnDiv( nDiv), fwidth(step), foffset(offset), + fDivisionType(divType), fmotherSolid( motherSolid ), fReflectedSolid(false), + fDeleteSolid(false), theVoluFirstCopyNo(1), fhgap(0.) +{ +#ifdef G4DIVDEBUG + if (verbose >= 1) + { + G4cout << " G4VDivisionParameterisation no divisions " << fnDiv + << " = " << nDiv << G4endl + << " offset " << foffset << " = " << offset << G4endl + << " step " << fwidth << " = " << step << G4endl; + } +#endif + kCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance(); +} + +//-------------------------------------------------------------------------- +G4VDivisionParameterisation::~G4VDivisionParameterisation() +{ + if (fDeleteSolid) delete fmotherSolid; +} + +//-------------------------------------------------------------------------- +G4VSolid* +G4VDivisionParameterisation:: +ComputeSolid( const G4int i, G4VPhysicalVolume* pv ) +{ + G4VSolid* solid = G4VPVParameterisation::ComputeSolid(i, pv); + if (solid->GetEntityType() == "G4ReflectedSolid") + { + solid = ((G4ReflectedSolid*)solid)->GetConstituentMovedSolid(); + } + return solid; +} + +//-------------------------------------------------------------------------- +void +G4VDivisionParameterisation:: +ChangeRotMatrix( G4VPhysicalVolume *physVol, G4double rotZ ) const +{ + static G4Mutex myMutex = G4MUTEX_INITIALIZER; + static std::map > frotTable; + + G4RotationMatrix *frot; + int threadId = G4Threading::G4GetThreadId(); + if (threadId < 0) { + frot = physVol->GetRotation(); + } + else { + G4AutoLock barrier(&myMutex); + frot = (G4RotationMatrix*)frotTable[threadId][physVol]; + if (frot == 0) { + frot = new G4RotationMatrix(); + physVol->SetRotation(frot); + frotTable[threadId][physVol] = frot; + } + } + *frot = G4RotationMatrix(); + frot->rotateZ( rotZ ); + +#if 0 + G4AutoLock barrier(&myMutex); + static std::map frot2physVol; + static std::map frot2threadId; + if (frot2physVol[frot] == 0) { + frot2physVol[frot] = physVol; + frot2threadId[frot] = threadId; + } + else if (frot2physVol[frot] != physVol || frot2threadId[frot] != threadId) { + G4cerr << "Hot diggitty dog!" << G4endl; + G4cerr << " bad frot = " << frot << G4endl; + G4cerr << " bad physVol = " << physVol << " =?= " << frot2physVol[frot] << G4endl; + G4cerr << " bad threadId = " << threadId << " =?= " << frot2threadId[frot] << G4endl; + frot2physVol[frot] = physVol; + frot2threadId[frot] = threadId; + } +#endif +} + +//-------------------------------------------------------------------------- +G4int +G4VDivisionParameterisation:: +CalculateNDiv( G4double motherDim, G4double width, G4double offset ) const +{ +#ifdef G4DIVDEBUG + G4cout << " G4VDivisionParameterisation::CalculateNDiv: " + << ( motherDim - offset ) / width + << " Motherdim: " << motherDim << ", Offset: " << offset + << ", Width: " << width << G4endl; +#endif + + return G4int( ( motherDim - offset ) / width ); +} + +//-------------------------------------------------------------------------- +G4double +G4VDivisionParameterisation:: +CalculateWidth( G4double motherDim, G4int nDiv, G4double offset ) const +{ +#ifdef G4DIVDEBUG + G4cout << " G4VDivisionParameterisation::CalculateWidth: " + << ( motherDim - offset ) / nDiv + << ", Motherdim: " << motherDim << ", Offset: " << offset + << ", Number of divisions: " << nDiv << G4endl; +#endif + + return ( motherDim - offset ) / nDiv; +} + +//-------------------------------------------------------------------------- +void G4VDivisionParameterisation::CheckParametersValidity() +{ + G4double maxPar = GetMaxParameter(); + CheckOffset( maxPar ); + CheckNDivAndWidth( maxPar ); +} + +//-------------------------------------------------------------------------- +void G4VDivisionParameterisation::CheckOffset( G4double maxPar ) +{ + if( foffset >= maxPar ) + { + std::ostringstream message; + message << "Configuration not supported." << G4endl + << "Division of solid " << fmotherSolid->GetName() + << " has too big offset = " << G4endl + << " " << foffset << " > " << maxPar << " !"; + G4Exception("G4VDivisionParameterisation::CheckOffset()", + "GeomDiv0001", FatalException, message); + } +} + +//-------------------------------------------------------------------------- +void G4VDivisionParameterisation::CheckNDivAndWidth( G4double maxPar ) +{ + if( (fDivisionType == DivNDIVandWIDTH) + && (foffset + fwidth*fnDiv - maxPar > kCarTolerance ) ) + { + std::ostringstream message; + message << "Configuration not supported." << G4endl + << "Division of solid " << fmotherSolid->GetName() + << " has too big offset + width*nDiv = " << G4endl + << " " << foffset + fwidth*fnDiv << " > " + << foffset << ". Width = " + << G4endl + << " " << fwidth << ". nDiv = " << fnDiv << " !"; + G4Exception("G4VDivisionParameterisation::CheckNDivAndWidth()", + "GeomDiv0001", FatalException, message); + } +} + +//-------------------------------------------------------------------------- +G4double G4VDivisionParameterisation::OffsetZ() const +{ + // take into account reflection in the offset + G4double offset = foffset; + if (fReflectedSolid) offset = GetMaxParameter() - fwidth*fnDiv - foffset; + + return offset; +} + + diff --git a/src/G4.9.6.p02fixes/G4ParallelWorldProcess.cc b/src/G4.9.6.p02fixes/G4ParallelWorldProcess.cc new file mode 100644 index 0000000..6025017 --- /dev/null +++ b/src/G4.9.6.p02fixes/G4ParallelWorldProcess.cc @@ -0,0 +1,430 @@ +// +// ******************************************************************** +// * 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: G4ParallelWorldProcess.cc 69966 2013-05-21 09:52:06Z gcosmo $ +// GEANT4 tag $Name: geant4-09-04-ref-00 $ +// +// + +#include "G4ios.hh" +#include "G4ParallelWorldProcess.hh" +#include "G4Step.hh" +#include "G4StepPoint.hh" +#include "G4Navigator.hh" +#include "G4VTouchable.hh" +#include "G4VPhysicalVolume.hh" +#include "G4ParticleChange.hh" +#include "G4PathFinder.hh" +#include "G4TransportationManager.hh" +#include "G4ParticleChange.hh" +#include "G4StepPoint.hh" +#include "G4FieldTrackUpdator.hh" +#include "G4Material.hh" +#include "G4ProductionCuts.hh" +#include "G4ProductionCutsTable.hh" + +#include "G4SDManager.hh" +#include "G4VSensitiveDetector.hh" + +G4Step* G4ParallelWorldProcess::fpHyperStep = 0; +G4int G4ParallelWorldProcess::nParallelWorlds = 0; +G4int G4ParallelWorldProcess::fNavIDHyp = 0; +const G4Step* G4ParallelWorldProcess::GetHyperStep() +{ return fpHyperStep; } +G4int G4ParallelWorldProcess::GetHypNavigatorID() +{ return fNavIDHyp; } + +G4ParallelWorldProcess:: +G4ParallelWorldProcess(const G4String& processName,G4ProcessType theType) +:G4VProcess(processName,theType), fGhostNavigator(0), fNavigatorID(-1), + fFieldTrack('0'),layeredMaterialFlag(false) +{ + if(!fpHyperStep) fpHyperStep = new G4Step(); + iParallelWorld = ++nParallelWorlds; + + pParticleChange = &aDummyParticleChange; + + fGhostStep = new G4Step(); + fGhostPreStepPoint = fGhostStep->GetPreStepPoint(); + fGhostPostStepPoint = fGhostStep->GetPostStepPoint(); + + fTransportationManager = G4TransportationManager::GetTransportationManager(); + fTransportationManager->GetNavigatorForTracking()->SetPushVerbosity(false); + fPathFinder = G4PathFinder::GetInstance(); + + if (verboseLevel>0) + { + G4cout << GetProcessName() << " is created " << G4endl; + } +} + +G4ParallelWorldProcess::~G4ParallelWorldProcess() +{ + delete fGhostStep; + nParallelWorlds--; + if(nParallelWorlds==0) + { + delete fpHyperStep; + fpHyperStep = 0; + } +} + +void G4ParallelWorldProcess:: +SetParallelWorld(G4String parallelWorldName) +{ + fGhostWorldName = parallelWorldName; + fGhostWorld = fTransportationManager->GetParallelWorld(fGhostWorldName); + fGhostNavigator = fTransportationManager->GetNavigator(fGhostWorld); + fGhostNavigator->SetPushVerbosity(false); +} + +void G4ParallelWorldProcess:: +SetParallelWorld(G4VPhysicalVolume* parallelWorld) +{ + fGhostWorldName = parallelWorld->GetName(); + fGhostWorld = parallelWorld; + fGhostNavigator = fTransportationManager->GetNavigator(fGhostWorld); + fGhostNavigator->SetPushVerbosity(false); +} + +void G4ParallelWorldProcess::StartTracking(G4Track* trk) +{ + if(fGhostNavigator) + { fNavigatorID = fTransportationManager->ActivateNavigator(fGhostNavigator); } + else + { + G4Exception("G4ParallelWorldProcess::StartTracking", + "ProcParaWorld000",FatalException, + "G4ParallelWorldProcess is used for tracking without having a parallel world assigned"); + } + fPathFinder->PrepareNewTrack(trk->GetPosition(),trk->GetMomentumDirection()); + + fOldGhostTouchable = fPathFinder->CreateTouchableHandle(fNavigatorID); + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fNewGhostTouchable = fOldGhostTouchable; + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + + fGhostSafety = -1.; + fOnBoundary = false; + fGhostPreStepPoint->SetStepStatus(fUndefined); + fGhostPostStepPoint->SetStepStatus(fUndefined); + +// G4VPhysicalVolume* thePhys = fNewGhostTouchable->GetVolume(); +// if(thePhys) +// { +// G4Material* ghostMaterial = thePhys->GetLogicalVolume()->GetMaterial(); +// if(ghostMaterial) +// { G4cout << " --- Material : " << ghostMaterial->GetName() << G4endl; } +// } + + *(fpHyperStep->GetPostStepPoint()) = *(trk->GetStep()->GetPostStepPoint()); + if(layeredMaterialFlag) + { + G4StepPoint* realWorldPostStepPoint = trk->GetStep()->GetPostStepPoint(); + SwitchMaterial(realWorldPostStepPoint); + G4StepPoint *realWorldPreStepPoint = trk->GetStep()->GetPreStepPoint(); + SwitchMaterial(realWorldPreStepPoint); + G4double velocity = trk->CalculateVelocity(); + realWorldPostStepPoint->SetVelocity(velocity); + realWorldPreStepPoint->SetVelocity(velocity); + trk->SetVelocity(velocity); + } + *(fpHyperStep->GetPreStepPoint()) = *(fpHyperStep->GetPostStepPoint()); +} + +G4double +G4ParallelWorldProcess::AtRestGetPhysicalInteractionLength( + const G4Track& /*track*/, + G4ForceCondition* condition) +{ +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// At Rest must be registered ONLY for the particle which has other At Rest +// process(es). +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + *condition = Forced; + return DBL_MAX; +} + +G4VParticleChange* G4ParallelWorldProcess::AtRestDoIt( + const G4Track& track, + const G4Step& step) +{ +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// At Rest must be registered ONLY for the particle which has other At Rest +// process(es). +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fOldGhostTouchable = fGhostPostStepPoint->GetTouchableHandle(); + G4VSensitiveDetector* aSD = 0; + if(fOldGhostTouchable->GetVolume()) + { aSD = fOldGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector(); } + fOnBoundary = false; + if(aSD) + { + CopyStep(step); + fGhostPreStepPoint->SetSensitiveDetector(aSD); + + fNewGhostTouchable = fOldGhostTouchable; + + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + if(fNewGhostTouchable->GetVolume()) + { + fGhostPostStepPoint->SetSensitiveDetector( + fNewGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector()); + } + else + { fGhostPostStepPoint->SetSensitiveDetector(0); } + + aSD->Hit(fGhostStep); + } + + pParticleChange->Initialize(track); + return pParticleChange; +} + +G4double +G4ParallelWorldProcess::PostStepGetPhysicalInteractionLength( + const G4Track& /*track*/, + G4double /*previousStepSize*/, + G4ForceCondition* condition) +{ + *condition = StronglyForced; + return DBL_MAX; +} + +G4VParticleChange* G4ParallelWorldProcess::PostStepDoIt( + const G4Track& track, + const G4Step& step) +{ + fOldGhostTouchable = fGhostPostStepPoint->GetTouchableHandle(); + G4VSensitiveDetector* aSD = 0; + if(fOldGhostTouchable->GetVolume()) + { aSD = fOldGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector(); } + CopyStep(step); + fGhostPreStepPoint->SetSensitiveDetector(aSD); + + if(fOnBoundary) + { + fNewGhostTouchable = fPathFinder->CreateTouchableHandle(fNavigatorID); + } + else + { + fNewGhostTouchable = fOldGhostTouchable; + } + + fGhostPreStepPoint->SetTouchableHandle(fOldGhostTouchable); + fGhostPostStepPoint->SetTouchableHandle(fNewGhostTouchable); + + if(fNewGhostTouchable->GetVolume()) + { + fGhostPostStepPoint->SetSensitiveDetector( + fNewGhostTouchable->GetVolume()->GetLogicalVolume()->GetSensitiveDetector()); + } + else + { fGhostPostStepPoint->SetSensitiveDetector(0); } + + G4VSensitiveDetector* sd = fGhostPreStepPoint->GetSensitiveDetector(); + if(sd) + { + sd->Hit(fGhostStep); + } + + pParticleChange->Initialize(track); + if(layeredMaterialFlag) + { + G4StepPoint* realWorldPostStepPoint = + ((G4Step*)(track.GetStep()))->GetPostStepPoint(); + SwitchMaterial(realWorldPostStepPoint); + } + return pParticleChange; +} + +G4double G4ParallelWorldProcess::AlongStepGetPhysicalInteractionLength( + const G4Track& track, G4double previousStepSize, G4double currentMinimumStep, + G4double& proposedSafety, G4GPILSelection* selection) +{ + static G4FieldTrack endTrack('0'); + //static ELimited eLimited; + ELimited eLimited; + ELimited eLim = kUndefLimited; + + *selection = NotCandidateForSelection; + G4double returnedStep = DBL_MAX; + + if (previousStepSize > 0.) + { fGhostSafety -= previousStepSize; } + if (fGhostSafety < 0.) fGhostSafety = 0.0; + + if (currentMinimumStep <= fGhostSafety && currentMinimumStep > 0.) + { + // I have no chance to limit + returnedStep = currentMinimumStep; + fOnBoundary = false; + proposedSafety = fGhostSafety - currentMinimumStep; + eLim = kDoNot; + } + else + { + G4FieldTrackUpdator::Update(&fFieldTrack,&track); + returnedStep + = fPathFinder->ComputeStep(fFieldTrack,currentMinimumStep,fNavigatorID, + track.GetCurrentStepNumber(),fGhostSafety,eLimited, + endTrack,track.GetVolume()); + if(eLimited == kDoNot) + { + fOnBoundary = false; + fGhostSafety = fGhostNavigator->ComputeSafety(endTrack.GetPosition()); + } + else + { + fOnBoundary = true; + } + proposedSafety = fGhostSafety; + if(eLimited == kUnique || eLimited == kSharedOther) { + *selection = CandidateForSelection; + } + else if (eLimited == kSharedTransport) { + returnedStep *= (1.0 + 1.0e-9); + } + eLim = eLimited; + } + + if(iParallelWorld==nParallelWorlds) fNavIDHyp = 0; + if(eLim == kUnique || eLim == kSharedOther) fNavIDHyp = fNavigatorID; + return returnedStep; +} + +G4VParticleChange* G4ParallelWorldProcess::AlongStepDoIt( + const G4Track& track, const G4Step& ) +{ + pParticleChange->Initialize(track); + return pParticleChange; +} + +void G4ParallelWorldProcess::CopyStep(const G4Step & step) +{ + G4StepStatus prevStat = fGhostPostStepPoint->GetStepStatus(); + + fGhostStep->SetTrack(step.GetTrack()); + fGhostStep->SetStepLength(step.GetStepLength()); + fGhostStep->SetTotalEnergyDeposit(step.GetTotalEnergyDeposit()); + fGhostStep->SetNonIonizingEnergyDeposit(step.GetNonIonizingEnergyDeposit()); + fGhostStep->SetControlFlag(step.GetControlFlag()); + + *fGhostPreStepPoint = *(step.GetPreStepPoint()); + *fGhostPostStepPoint = *(step.GetPostStepPoint()); + + fGhostPreStepPoint->SetStepStatus(prevStat); + if(fOnBoundary) + { fGhostPostStepPoint->SetStepStatus(fGeomBoundary); } + else if(fGhostPostStepPoint->GetStepStatus()==fGeomBoundary) + { fGhostPostStepPoint->SetStepStatus(fPostStepDoItProc); } + + if(iParallelWorld==1) + { + G4StepStatus prevStatHyp = fpHyperStep->GetPostStepPoint()->GetStepStatus(); + + fpHyperStep->SetTrack(step.GetTrack()); + fpHyperStep->SetStepLength(step.GetStepLength()); + fpHyperStep->SetTotalEnergyDeposit(step.GetTotalEnergyDeposit()); + fpHyperStep->SetNonIonizingEnergyDeposit(step.GetNonIonizingEnergyDeposit()); + fpHyperStep->SetControlFlag(step.GetControlFlag()); + + *(fpHyperStep->GetPreStepPoint()) = *(fpHyperStep->GetPostStepPoint()); + *(fpHyperStep->GetPostStepPoint()) = *(step.GetPostStepPoint()); + + fpHyperStep->GetPreStepPoint()->SetStepStatus(prevStatHyp); + } + + if(fOnBoundary) + { fpHyperStep->GetPostStepPoint()->SetStepStatus(fGeomBoundary); } +} + +void G4ParallelWorldProcess::SwitchMaterial(G4StepPoint* realWorldStepPoint) +{ + if(realWorldStepPoint->GetStepStatus()==fWorldBoundary) return; + G4VPhysicalVolume* thePhys = fNewGhostTouchable->GetVolume(); + if(thePhys) + { + G4Material* ghostMaterial = thePhys->GetLogicalVolume()->GetMaterial(); + if(ghostMaterial) + { + G4Region* ghostRegion = thePhys->GetLogicalVolume()->GetRegion(); + G4ProductionCuts* prodCuts = + realWorldStepPoint->GetMaterialCutsCouple()->GetProductionCuts(); + if(ghostRegion) + { + G4ProductionCuts* ghostProdCuts = ghostRegion->GetProductionCuts(); + if(ghostProdCuts) prodCuts = ghostProdCuts; + } + const G4MaterialCutsCouple* ghostMCCouple = + G4ProductionCutsTable::GetProductionCutsTable() + ->GetMaterialCutsCouple(ghostMaterial,prodCuts); + if(ghostMCCouple) + { + realWorldStepPoint->SetMaterial(ghostMaterial); + realWorldStepPoint->SetMaterialCutsCouple(ghostMCCouple); + *(fpHyperStep->GetPostStepPoint()) = *(fGhostPostStepPoint); + fpHyperStep->GetPostStepPoint()->SetMaterial(ghostMaterial); + fpHyperStep->GetPostStepPoint()->SetMaterialCutsCouple(ghostMCCouple); + } + else + { + G4cout << "!!! MaterialCutsCouple is not found for " + << ghostMaterial->GetName() << "." << G4endl + << " Material in real world (" + << realWorldStepPoint->GetMaterial()->GetName() + << ") is used." << G4endl; + } + } + } +} + +G4bool G4ParallelWorldProcess::IsAtRestRequired(G4ParticleDefinition* partDef) +{ + G4int pdgCode = partDef->GetPDGEncoding(); + if(pdgCode==0) + { + G4String partName = partDef->GetParticleName(); + if(partName=="opticalphoton") return false; + if(partName=="geantino") return false; + if(partName=="chargedgeantino") return false; + } + else + { + if(pdgCode==22) return false; // gamma + if(pdgCode==11) return false; // electron + if(pdgCode==2212) return false; // proton + if(pdgCode==-12) return false; // anti_nu_e + if(pdgCode==12) return false; // nu_e + if(pdgCode==-14) return false; // anti_nu_mu + if(pdgCode==14) return false; // nu_mu + if(pdgCode==-16) return false; // anti_nu_tau + if(pdgCode==16) return false; // nu_tau + } + return true; +} + diff --git a/src/GlueXBeamConversionProcess.cc b/src/GlueXBeamConversionProcess.cc index 0f8130d..8e16871 100644 --- a/src/GlueXBeamConversionProcess.cc +++ b/src/GlueXBeamConversionProcess.cc @@ -12,11 +12,13 @@ #include "GlueXUserOptions.hh" #include "GlueXPathFinder.hh" -// Jack up this threshold to 20GeV to disable this feature -// and let your application run without Dirac++ support, or -// otherwise just remove the PTAR target from the beamline -// in the hdds geometry. -#define FORCED_PTAR_PAIR_CONVERSION_THRESHOLD 3*GeV +#define VERBOSE_PAIRS_SPLITTING 1 +#define DO_PAIRCOH_IMPORTANCE_SAMPLE 1 + +// If you set this flag to 1 then all beam photons that reach +// the TPOL converter target will convert to e+e- pairs inside, +// otherwise the standard pair conversion probabilities apply. +#define FORCED_PTAR_PAIR_CONVERSION 0 #include #include "G4Positron.hh" @@ -26,6 +28,7 @@ #include "G4Gamma.hh" #include +#include #ifdef USING_DIRACXX #include @@ -50,8 +53,8 @@ GlueXBeamConversionProcess::GlueXBeamConversionProcess(const G4String &name, exit(-1); } - fStopBeamBeforeConversion = 0; - fStopBeamAfterConversion = 0; + fStopBeamBeforeConverter = 0; + fStopBeamAfterConverter = 0; std::map infile; std::map beampars; @@ -66,7 +69,7 @@ GlueXBeamConversionProcess::GlueXBeamConversionProcess(const G4String &name, genbeampars[1] == "Postcol" || genbeampars[1] == "PostCol" )) { - fStopBeamBeforeConversion = 1; + fStopBeamBeforeConverter = 1; } else if (genbeampars.find(1) != genbeampars.end() && (genbeampars[1] == "POSTCONV" || @@ -74,7 +77,7 @@ GlueXBeamConversionProcess::GlueXBeamConversionProcess(const G4String &name, genbeampars[1] == "Postconv" || genbeampars[1] == "PostConv" )) { - fStopBeamAfterConversion = 1; + fStopBeamAfterConverter = 1; } } @@ -83,16 +86,24 @@ GlueXBeamConversionProcess::GlueXBeamConversionProcess(const G4String &name, fPairsGeneration = new PairConversionGeneration(); #endif - fPaircohPDF.Pcut = 10; - fTripletPDF.Pcut = 2.5; + fPaircohPDF.Pcut = 60; + fTripletPDF.Pcut = 15; + + if (verboseLevel > 0) { + G4cout << GetProcessName() << " is created " << G4endl + << " Stop beam before converter? " + << (fStopBeamBeforeConverter? "yes" : "no") << G4endl + << " Stop beam after converter? " + << (fStopBeamAfterConverter? "yes" : "no") << G4endl; + } } GlueXBeamConversionProcess::GlueXBeamConversionProcess( GlueXBeamConversionProcess &src) : G4VDiscreteProcess(src) { - fStopBeamBeforeConversion = src.fStopBeamBeforeConversion; - fStopBeamAfterConversion = src.fStopBeamAfterConversion; + fStopBeamBeforeConverter = src.fStopBeamBeforeConverter; + fStopBeamAfterConverter = src.fStopBeamAfterConverter; fPaircohPDF.Pcut = src.fPaircohPDF.Pcut; fTripletPDF.Pcut = src.fTripletPDF.Pcut; } @@ -120,15 +131,15 @@ G4double GlueXBeamConversionProcess::PostStepGetPhysicalInteractionLength( G4double previousStepSize, G4ForceCondition *condition) { -#if DISABLE_FOR_DEBUGGING G4VPhysicalVolume *pvol = GlueXPathFinder::GetLocatedVolume(); - if (pvol && pvol->GetName() == "PTAR" && track.GetTrackID() == 1 && - track.GetKineticEnergy() > FORCED_PTAR_PAIR_CONVERSION_THRESHOLD) + if (track.GetTrackID() == 1 && pvol && pvol->GetName() == "PTAR" && + (FORCED_PTAR_PAIR_CONVERSION || + fStopBeamBeforeConverter || + fStopBeamAfterConverter )) { *condition = Forced; return 100*cm; } -#endif *condition = NotForced; return 1e99; } @@ -141,7 +152,7 @@ G4VParticleChange *GlueXBeamConversionProcess::PostStepDoIt( GlueXUserEventInformation *eventinfo; const G4Event *event = G4RunManager::GetRunManager()->GetCurrentEvent(); eventinfo = (GlueXUserEventInformation*)event->GetUserInformation(); - if (fStopBeamBeforeConversion) { + if (fStopBeamBeforeConverter) { double tvtx = step.GetPreStepPoint()->GetGlobalTime(); G4ThreeVector vtx = step.GetPreStepPoint()->GetPosition(); G4ThreeVector mom = step.GetPreStepPoint()->GetMomentum(); @@ -153,24 +164,41 @@ G4VParticleChange *GlueXBeamConversionProcess::PostStepDoIt( vertex->SetPrimary(photon); eventinfo->AddPrimaryVertex(*vertex); eventinfo->AddBeamParticle(1, tvtx, vtx, mom, pol); + + if (verboseLevel > 0) { + G4cout << "GlueXBeamConversionProcess: beam particle stopped" + << " before converter, stored in ouptut primary vertex." + << G4endl; + } } - else if (fStopBeamAfterConversion) { + else if (fStopBeamAfterConverter) { double tvtx = step.GetPreStepPoint()->GetGlobalTime(); G4ThreeVector vtx = step.GetPreStepPoint()->GetPosition(); G4ThreeVector mom = step.GetPreStepPoint()->GetMomentum(); G4ThreeVector pol = step.GetPreStepPoint()->GetPolarization(); eventinfo->AddBeamParticle(1, tvtx, vtx, mom, pol); GenerateBeamPairConversion(step); + + if (verboseLevel > 0) { + G4cout << "GlueXBeamConversionProcess: beam particle stopped" + << " at converter exit, pair conversion forced." + << G4endl; + } } else { GenerateBeamPairConversion(step); + + if (verboseLevel > 0) { + G4cout << "GlueXBeamConversionProcess: beam particle stopped" + << " unexpectedly, pair conversion forced. But WHY?" + << G4endl; + } } pParticleChange->ProposeTrackStatus(fStopAndKill); eventinfo->SetKeepEvent(1); return pParticleChange; } - void GlueXBeamConversionProcess::prepareImportanceSamplingPDFs() { // Construct lookup tables representing the PDFs used for @@ -184,7 +212,7 @@ void GlueXBeamConversionProcess::prepareImportanceSamplingPDFs() #if USING_DIRACXX - double kin = 9.; // GeV + LDouble_t kin = 9.; // GeV TPhoton g0; TLepton p1(mElectron); TLepton e2(mElectron); @@ -196,30 +224,30 @@ void GlueXBeamConversionProcess::prepareImportanceSamplingPDFs() e2.AllPol(); e3.AllPol(); - double Epos = kin / 2; - double Mmin = 2 * mElectron; - double Mcut = 5e-3; // 5 MeV cutoff parameter - double um0 = 1 + sqr(Mcut / Mmin); - double qRcut = 1e-3; // 1 MeV/c cutoff parameter + LDouble_t Epos = kin / 2; + LDouble_t Mmin = 2 * mElectron; + LDouble_t Mcut = 5e-3; // 5 MeV cutoff parameter + LDouble_t um0 = 1 + sqr(Mcut / Mmin); + LDouble_t qRcut = 1e-3; // 1 MeV/c cutoff parameter int Nbins = 50; fTripletPDF.Psum = 0; fPaircohPDF.Psum = 0; for (int i0=0; i0 < Nbins; ++i0) { - double u0 = (i0 + 0.5) / Nbins; - double um = pow(um0, u0); - double Mpair = Mcut / sqrt(um - 1); - double k12star2 = sqr(Mpair / 2) - sqr(mElectron); - double qRmin = sqr(Mpair) / (2 * kin); - double uq0 = qRmin / (qRcut + sqrt(sqr(qRcut) + sqr(qRmin))); - double weight0 = sqr(Mpair) * (sqr(Mcut) + sqr(Mpair)); + LDouble_t u0 = (i0 + 0.5) / Nbins; + LDouble_t um = pow(um0, u0); + LDouble_t Mpair = Mcut / sqrt(um - 1); + LDouble_t k12star2 = sqr(Mpair / 2) - sqr(mElectron); + LDouble_t qRmin = sqr(Mpair) / (2 * kin); + LDouble_t uq0 = qRmin / (qRcut + sqrt(sqr(qRcut) + sqr(qRmin))); + LDouble_t weight0 = sqr(Mpair) * (sqr(Mcut) + sqr(Mpair)); for (int i1=0; i1 < Nbins; ++i1) { - double u1 = (i1 + 0.5) / Nbins; - double uq = pow(uq0, u1); - double qR = 2 * qRcut * uq / (1 - sqr(uq)); - double weight = weight0 * sqr(qR) * sqrt(sqr(qRcut) + sqr(qR)); - double E3 = sqrt(sqr(qR) + sqr(mElectron)); - double E12 = kin + mElectron - E3; + LDouble_t u1 = (i1 + 0.5) / Nbins; + LDouble_t uq = pow(uq0, u1); + LDouble_t qR = 2 * qRcut * uq / (1 - sqr(uq)); + LDouble_t weight = weight0 * sqr(qR) * sqrt(sqr(qRcut) + sqr(qR)); + LDouble_t E3 = sqrt(sqr(qR) + sqr(mElectron)); + LDouble_t E12 = kin + mElectron - E3; if (k12star2 < 0 || E12 < Mpair) { fPaircohPDF.density.push_back(0); fTripletPDF.density.push_back(0); @@ -227,12 +255,12 @@ void GlueXBeamConversionProcess::prepareImportanceSamplingPDFs() fTripletPDF.integral.push_back(fTripletPDF.Psum); continue; } - double k12star = sqrt(k12star2); - double q12mag = sqrt(sqr(E12) - sqr(Mpair)); - double costhetastar = (Epos - E12 / 2) * - Mpair / (k12star * q12mag); - double costhetaR = (sqr(Mpair) / 2 + (kin + mElectron) * - (E3 - mElectron)) / (kin * qR); + LDouble_t k12star = sqrt(k12star2); + LDouble_t q12mag = sqrt(sqr(E12) - sqr(Mpair)); + LDouble_t costhetastar = (Epos - E12 / 2) * + Mpair / (k12star * q12mag); + LDouble_t costhetaR = (sqr(Mpair) / 2 + (kin + mElectron) * + (E3 - mElectron)) / (kin * qR); if (fabs(costhetastar) > 1 || fabs(costhetaR) > 1) { fPaircohPDF.density.push_back(0); fTripletPDF.density.push_back(0); @@ -240,10 +268,10 @@ void GlueXBeamConversionProcess::prepareImportanceSamplingPDFs() fTripletPDF.integral.push_back(fTripletPDF.Psum); continue; } - double qRlong = qR * costhetaR; - double qRperp = sqrt(sqr(qR) - sqr(qRlong)); + LDouble_t qRlong = qR * costhetaR; + LDouble_t qRperp = sqrt(sqr(qR) - sqr(qRlong)); TThreeVectorReal q3(0, qRperp, qRlong); - double sinthetastar = sqrt(1 - sqr(costhetastar)); + LDouble_t sinthetastar = sqrt(1 - sqr(costhetastar)); TThreeVectorReal k12(k12star * sinthetastar, 0, k12star * costhetastar); TFourVectorReal q1(Mpair / 2, k12); @@ -254,8 +282,8 @@ void GlueXBeamConversionProcess::prepareImportanceSamplingPDFs() p1.SetMom(q1); e2.SetMom(q2); e3.SetMom(q3); - double tripXS = fPairsGeneration->DiffXS_triplet(g0,p1,e2,e3); - double pairXS = fPairsGeneration->DiffXS_pair(g0,p1,e2); + LDouble_t tripXS = fPairsGeneration->DiffXS_triplet(g0,p1,e2,e3); + LDouble_t pairXS = fPairsGeneration->DiffXS_pair(g0,p1,e2); fTripletPDF.Psum += fTripletPDF.Pmax = tripXS * weight; fPaircohPDF.Psum += fPaircohPDF.Pmax = pairXS * weight; fTripletPDF.density.push_back(fTripletPDF.Pmax); @@ -265,10 +293,10 @@ void GlueXBeamConversionProcess::prepareImportanceSamplingPDFs() } } - double du2 = 1. / sqr(Nbins); + LDouble_t du2 = 1. / sqr(Nbins); for (int i0=0, index=0; i0 < Nbins; ++i0) { for (int i1=0; i1 < Nbins; ++i1, ++index) { - double randvar = i0 + (i1 + 0.5) / Nbins; + LDouble_t randvar = i0 + (i1 + 0.5) / Nbins; fTripletPDF.randvar.push_back(randvar); fPaircohPDF.randvar.push_back(randvar); fTripletPDF.density[index] /= fTripletPDF.Psum * du2; @@ -336,48 +364,54 @@ void GlueXBeamConversionProcess::GenerateBeamPairConversion(const G4Step &step) e2.AllPol(); e3.AllPol(); const G4Track *track = step.GetTrack(); - double kin = track->GetKineticEnergy()/GeV; + LDouble_t kin = track->GetKineticEnergy()/GeV; + + // If we are below pair production threshold, do nothing + const double mTarget = step.GetPreStepPoint()->GetMaterial()->GetA() * 0.932; + if (kin < 2 * mElectron * (1 + mElectron / mTarget)) + return; + G4ThreeVector mom(track->GetMomentum()); TThreeVectorReal mom0(mom[0]/GeV, mom[1]/GeV, mom[2]/GeV); gIn.SetMom(mom0); G4ThreeVector pol(track->GetPolarization()); TThreeVectorReal pol0(pol[0], pol[1], pol[2]); - gIn.SetPol(pol0); + gIn.SetPlanePolarization(pol0, pol0.Length()); // Define an angle and axis that rotates zhat into the direction - // of the incidentn gamma, so that the generated kinematics is + // of the incident gamma, so that the generated kinematics is // defined with the incident gamma aligned with zhat, and then // rotated at the end into the final spatial direction. TThreeVectorReal rockaxis(mom0); rockaxis.Cross(TThreeVectorReal(0,0,1)); - double rockangle = rockaxis.Length() / kin; + double rockangle = rockaxis.Length() / mom0.Length(); rockaxis /= rockaxis.Length(); while (true) { - double weight = 1; + LDouble_t weight = 1; // Generate uniform in E+, phi12, phiR - double Epos = kin * G4UniformRand(); + LDouble_t Epos = kin * G4UniformRand(); while (Epos < mElectron) { Epos = kin * G4UniformRand(); } weight *= kin - mElectron; - double phi12 = 2*M_PI * G4UniformRand(); + LDouble_t phi12 = 2*M_PI * G4UniformRand(); weight *= 2*M_PI; - double phiR = 2*M_PI * G4UniformRand(); + LDouble_t phiR = 2*M_PI * G4UniformRand(); weight *= 2*M_PI; - double u0 = G4UniformRand(); - double u1 = G4UniformRand(); + LDouble_t u0 = G4UniformRand(); + LDouble_t u1 = G4UniformRand(); #if DO_TRIPLET_IMPORTANCE_SAMPLE int i = fTripletPDF.search(u1); - double fi = fTripletPDF.density[i]; - double ui = fTripletPDF.integral[i]; - double ri = fTripletPDF.randvar[i]; - double xi = ri - floor(ri); - double dx = (xi > 0.5)? ri - fTripletPDF.randvar[i-1]: + LDouble_t fi = fTripletPDF.density[i]; + LDouble_t ui = fTripletPDF.integral[i]; + LDouble_t ri = fTripletPDF.randvar[i]; + LDouble_t xi = ri - floor(ri); + LDouble_t dx = (xi > 0.5)? ri - fTripletPDF.randvar[i-1]: fTripletPDF.randvar[i+1] - ri; u1 = xi + dx / 2 - (ui - u1) / (fi * dx); u0 = (u0 + floor(ri)) * dx; @@ -386,11 +420,11 @@ void GlueXBeamConversionProcess::GenerateBeamPairConversion(const G4Step &step) #elif DO_PAIRCOH_IMPORTANCE_SAMPLE int i = fPaircohPDF.search(u1); - double fi = fPaircohPDF.density[i]; - double ui = fPaircohPDF.integral[i]; - double ri = fPaircohPDF.randvar[i]; - double xi = ri - floor(ri); - double dx = (xi > 0.5)? ri - fPaircohPDF.randvar[i-1]: + LDouble_t fi = fPaircohPDF.density[i]; + LDouble_t ui = fPaircohPDF.integral[i]; + LDouble_t ri = fPaircohPDF.randvar[i]; + LDouble_t xi = ri - floor(ri); + LDouble_t dx = (xi > 0.5)? ri - fPaircohPDF.randvar[i-1]: fPaircohPDF.randvar[i+1] - ri; u1 = xi + dx / 2 - (ui - u1) / (fi * dx); u0 = (u0 + floor(ri)) * dx; @@ -399,48 +433,48 @@ void GlueXBeamConversionProcess::GenerateBeamPairConversion(const G4Step &step) #endif // Generate Mpair as 1 / (M [M^2 + Mcut^2]) - double Mmin = 2 * mElectron; - double Mcut = 0.005; // GeV - double um0 = 1 + sqr(Mcut / Mmin); - double um = pow(um0, u0); - double Mpair = Mcut / sqrt(um - 1 + 1e-99); + LDouble_t Mmin = 2 * mElectron; + LDouble_t Mcut = 0.005; // GeV + LDouble_t um0 = 1 + sqr(Mcut / Mmin); + LDouble_t um = pow(um0, u0); + LDouble_t Mpair = Mcut / sqrt(um - 1 + 1e-99); weight *= Mpair * (sqr(Mcut) + sqr(Mpair)) * log(um0) / (2 * sqr(Mcut)); // Generate qR^2 with weight 1 / [qR^2 sqrt(qRcut^2 + qR^2)] - double qRmin = sqr(Mpair) /(2 * kin); - double qRcut = 1e-3; // GeV - double uq0 = qRmin / (qRcut + sqrt(sqr(qRcut) + sqr(qRmin))); - double uq = pow(uq0, u1); - double qR = 2 * qRcut * uq / (1 - sqr(uq)); - double qR2 = qR * qR; + LDouble_t qRmin = sqr(Mpair) /(2 * kin); + LDouble_t qRcut = 1e-3; // GeV + LDouble_t uq0 = qRmin / (qRcut + sqrt(sqr(qRcut) + sqr(qRmin))); + LDouble_t uq = pow(uq0, u1); + LDouble_t qR = 2 * qRcut * uq / (1 - sqr(uq)); + LDouble_t qR2 = qR * qR; weight *= qR2 * sqrt(1 + qR2 / sqr(qRcut)) * (-2 * log(uq0)); // Include overall measure Jacobian factor weight *= Mpair / (2 * kin); // Generate with importance sampling - double Striplet = fTripletPDF.Npassed * + LDouble_t Striplet = fTripletPDF.Npassed * (fTripletPDF.Ntested / (fTripletPDF.Psum + 1e-99)); - double Spaircoh = fPaircohPDF.Npassed * + LDouble_t Spaircoh = fPaircohPDF.Npassed * (fPaircohPDF.Ntested / (fPaircohPDF.Psum + 1e-99)); if (Striplet < Spaircoh) { // try incoherent generation ++fTripletPDF.Ntested; // Solve for the c.m. momentum of e+ in the pair 1,2 rest frame - double k12star2 = sqr(Mpair / 2) - sqr(mElectron); + LDouble_t k12star2 = sqr(Mpair / 2) - sqr(mElectron); if (k12star2 < 0) { // try again (this should never happen!) continue; } - double k12star = sqrt(k12star2); - double E3 = sqrt(qR2 + sqr(mElectron)); - double E12 = kin + mElectron - E3; + LDouble_t k12star = sqrt(k12star2); + LDouble_t E3 = sqrt(qR2 + sqr(mElectron)); + LDouble_t E12 = kin + mElectron - E3; if (E12 < Mpair) { // no kinematic solution because E12 < Mpair, try again continue; } - double q12mag = sqrt(sqr(E12) - sqr(Mpair)); - double costhetastar = (Epos - E12 / 2) * Mpair / (k12star * q12mag); + LDouble_t q12mag = sqrt(sqr(E12) - sqr(Mpair)); + LDouble_t costhetastar = (Epos - E12 / 2) * Mpair / (k12star * q12mag); if (Epos > E12 - mElectron) { // no kinematic solution because Epos > E12 - mElectron, try again continue; @@ -451,19 +485,19 @@ void GlueXBeamConversionProcess::GenerateBeamPairConversion(const G4Step &step) } // Solve for the recoil electron kinematics - double costhetaR = (sqr(Mpair) / 2 + (kin + mElectron) * + LDouble_t costhetaR = (sqr(Mpair) / 2 + (kin + mElectron) * (E3 - mElectron)) / (kin * qR); if (fabs(costhetaR) > 1) { // no kinematic solution because |costhetaR| > 1, try again continue; } - double sinthetaR = sqrt(1 - sqr(costhetaR)); + LDouble_t sinthetaR = sqrt(1 - sqr(costhetaR)); TFourVectorReal q3(E3, qR * sinthetaR * cos(phiR), qR * sinthetaR * sin(phiR), qR * costhetaR); // Boost the pair momenta into the lab - double sinthetastar = sqrt(1 - sqr(costhetastar)); + LDouble_t sinthetastar = sqrt(1 - sqr(costhetastar)); TThreeVectorReal k12(k12star * sinthetastar * cos(phi12), k12star * sinthetastar * sin(phi12), k12star * costhetastar); @@ -480,15 +514,31 @@ void GlueXBeamConversionProcess::GenerateBeamPairConversion(const G4Step &step) continue; } - // Compute the differential cross section (barnes/GeV^4) + // Compute the differential cross section (barns/GeV^4) // returned as d(sigma)/(dE+ dphi+ d^3qR) p1.SetMom(q1.Rotate(rockaxis, rockangle)); e2.SetMom(q2.Rotate(rockaxis, rockangle)); e3.SetMom(q3.Rotate(rockaxis, rockangle)); - double diffXS = fPairsGeneration->DiffXS_triplet(gIn, p1, e2, e3); - + + TFourVectorReal pIn, pOut; + TFourVectorReal::SetResolution(1e-10); + pIn = gIn.Mom() + TFourVectorReal(mElectron,0,0,0); + pOut = p1.Mom() + e2.Mom() + e3.Mom(); + if (pIn != pOut) { + G4cout << "Warning in GenerateBeamPairConversion - " + << "momentum conservation violated." << std::endl + << " pIn = "; + pIn.Print(); + G4cout << " pOut = "; + pOut.Print(); + G4cout << " pIn - pOut = "; + (pIn-pOut).Print(); + } + + LDouble_t diffXS = fPairsGeneration->DiffXS_triplet(gIn, p1, e2, e3); + // Use keep/discard algorithm - double Pfactor = diffXS * weight; + LDouble_t Pfactor = diffXS * weight; if (Pfactor > fTripletPDF.Pmax) fTripletPDF.Pmax = Pfactor; if (Pfactor > fTripletPDF.Pcut) { @@ -517,13 +567,13 @@ void GlueXBeamConversionProcess::GenerateBeamPairConversion(const G4Step &step) // Solve for the c.m. momentum of e+ in the pair 1,2 rest frame // assuming that the atomic target absorbs zero energy - double k12star2 = sqr(Mpair / 2) - sqr(mElectron); + LDouble_t k12star2 = sqr(Mpair / 2) - sqr(mElectron); if (k12star2 < 0) { // try again (this should never happen!) continue; } - double k12star = sqrt(k12star2); - double Eele = kin - Epos; + LDouble_t k12star = sqrt(k12star2); + LDouble_t Eele = kin - Epos; if (kin < Mpair) { // no kinematic solution because kin < Mpair, try again continue; @@ -532,26 +582,26 @@ void GlueXBeamConversionProcess::GenerateBeamPairConversion(const G4Step &step) // no kinematic solution because Eele < mElectron, try again continue; } - double q12mag = sqrt(sqr(kin) - sqr(Mpair)); - double costhetastar = (Epos - kin / 2) * Mpair / (k12star * q12mag); + LDouble_t q12mag = sqrt(sqr(kin) - sqr(Mpair)); + LDouble_t costhetastar = (Epos - kin / 2) * Mpair / (k12star * q12mag); if (fabs(costhetastar) > 1) { // no kinematic solution because |costhetastar| > 1, try again continue; } // Solve for the recoil kinematics kinematics - double costhetaR = (sqr(Mpair) + qR2) / (2 * kin * qR); + LDouble_t costhetaR = (sqr(Mpair) + qR2) / (2 * kin * qR); if (fabs(costhetaR) > 1) { // no kinematic solution because |costhetaR| > 1, try again continue; } - double sinthetaR = sqrt(1 - sqr(costhetaR)); + LDouble_t sinthetaR = sqrt(1 - sqr(costhetaR)); TThreeVectorReal q3(qR * sinthetaR * cos(phiR), qR * sinthetaR * sin(phiR), qR * costhetaR); // Boost the pair momenta into the lab - double sinthetastar = sqrt(1 - sqr(costhetastar)); + LDouble_t sinthetastar = sqrt(1 - sqr(costhetastar)); TThreeVectorReal k12(k12star * sinthetastar * cos(phi12), k12star * sinthetastar * sin(phi12), k12star * costhetastar); @@ -566,10 +616,10 @@ void GlueXBeamConversionProcess::GenerateBeamPairConversion(const G4Step &step) p1.SetMom(q1.Rotate(rockaxis, rockangle)); e2.SetMom(q2.Rotate(rockaxis, rockangle)); e3.SetMom(TThreeVectorReal(0,0,0)); - double diffXS = fPairsGeneration->DiffXS_pair(gIn, p1, e2); + LDouble_t diffXS = fPairsGeneration->DiffXS_pair(gIn, p1, e2); // Use keep/discard algorithm - double Pfactor = diffXS * weight; + LDouble_t Pfactor = diffXS * weight; if (Pfactor > fPaircohPDF.Pmax) fPaircohPDF.Pmax = Pfactor; if (Pfactor > fPaircohPDF.Pcut) { @@ -629,7 +679,7 @@ void GlueXBeamConversionProcess::GenerateBeamPairConversion(const G4Step &step) trackinfo->SetGlueXTrackID(event_info->AssignNextGlueXTrackID()); } (*iter)->SetUserInformation(trackinfo); - if (fStopBeamAfterConversion == 0) { + if (fStopBeamAfterConverter == 0) { pParticleChange->AddSecondary(*iter); } } @@ -643,15 +693,20 @@ void GlueXBeamConversionProcess::GenerateBeamPairConversion(const G4Step &step) } #if VERBOSE_PAIRS_SPLITTING - if (fTripletPDF.Npassed / 100 * 100 == fTripletPDF.Npassed) { - G4cout << "triplet rate is " - << fTripletPDF.Psum / (fTripletPDF.Ntested + 1e-99) - << ", efficiency is " + if ((fTripletPDF.Npassed + fPaircohPDF.Npassed) % 500 == 0) { + G4cout << std::setprecision(5) + << "triplet cross section is " << fTripletPDF.Pcut * + fTripletPDF.Npassed / (fTripletPDF.Ntested + 1e-99) + << " +/- " << fTripletPDF.Pcut * + sqrt(fTripletPDF.Npassed) / (fTripletPDF.Ntested + 1e-99) + << " barns, efficiency is " << fTripletPDF.Npassed / (fTripletPDF.Ntested + 1e-99) << G4endl - << "pair rate is " - << fPaircohPDF.Psum / (fPaircohPDF.Ntested + 1e-99) - << ", efficiency is " + << "pair cross section is " << fPaircohPDF.Pcut * + fPaircohPDF.Npassed / (fPaircohPDF.Ntested + 1e-99) + << " +/- " << fPaircohPDF.Pcut * + sqrt(fPaircohPDF.Npassed) / (fPaircohPDF.Ntested + 1e-99) + << " barns, efficiency is " << fPaircohPDF.Npassed / (fPaircohPDF.Ntested + 1e-99) << G4endl << "counts are " diff --git a/src/GlueXBeamConversionProcess.hh b/src/GlueXBeamConversionProcess.hh index 72ac45d..ac91b6d 100644 --- a/src/GlueXBeamConversionProcess.hh +++ b/src/GlueXBeamConversionProcess.hh @@ -45,8 +45,8 @@ class GlueXBeamConversionProcess: public G4VDiscreteProcess static PairConversionGeneration *fPairsGeneration; #endif - int fStopBeamBeforeConversion; - int fStopBeamAfterConversion; + int fStopBeamBeforeConverter; + int fStopBeamAfterConverter; void prepareImportanceSamplingPDFs(); diff --git a/src/GlueXDetectorConstruction.cc b/src/GlueXDetectorConstruction.cc index a778e2e..78153f0 100644 --- a/src/GlueXDetectorConstruction.cc +++ b/src/GlueXDetectorConstruction.cc @@ -7,6 +7,7 @@ #include "GlueXDetectorConstruction.hh" #include "GlueXDetectorMessenger.hh" #include "GlueXMagneticField.hh" +#include "HddmOutput.hh" #include "GlueXSensitiveDetectorCDC.hh" #include "GlueXSensitiveDetectorFDC.hh" @@ -73,7 +74,8 @@ std::list GlueXDetectorConstruction::fInstance; GlueXDetectorConstruction::GlueXDetectorConstruction(G4String hddsFile) : fMaxStep(0), fUniformField(0), - fpMagneticField(0) + fpMagneticField(0), + fGeometryXML(0) { G4AutoLock barrier(&fMutex); fInstance.push_back(this); @@ -99,51 +101,59 @@ GlueXDetectorConstruction::GlueXDetectorConstruction(G4String hddsFile) return; } - XString xmlFile; + DOMDocument* document; if (hddsFile.size() > 0) { - xmlFile = hddsFile.c_str(); + int size=100; + char *saved_cwd = new char[size]; + while (getcwd(saved_cwd, size) == 0) + { + delete [] saved_cwd; + saved_cwd = new char[size *= 2]; + } + XString xmlFile = hddsFile.c_str(); + char *dirpath = new char[hddsFile.size() + 2]; + chdir(dirname(strcpy(dirpath, hddsFile.c_str()))); + document = buildDOMDocument(xmlFile,false); + chdir(saved_cwd); + delete [] saved_cwd; + delete [] dirpath; } else if (getenv("JANA_GEOMETRY_URL")) { - hddsFile = getenv("JANA_GEOMETRY_URL"); - if (hddsFile.index("xmlfile://") == 0) - { - hddsFile.remove(0,10); - xmlFile = hddsFile.c_str(); - } - else +#ifndef FORCE_HDDS_FILES_PARSING + std::string url = getenv("JANA_GEOMETRY_URL"); + int run = HddmOutput::getRunNo(); + fGeometryXML = new HddsGeometryXML(url, run); + last_md5_checksum = fGeometryXML->GetChecksum(); + document = fGeometryXML->getDocument(); +#else + int size=100; + char *saved_cwd = new char[size]; + while (getcwd(saved_cwd, size) == 0) { - G4cerr << APP_NAME << " - unsupported protocol for JANA_GEOMETRY_URL" - << G4endl << getenv("JANA_GEOMETRY_URL") << G4endl; - return; + delete [] saved_cwd; + saved_cwd = new char[size *= 2]; } + XString hddsdir = getenv("HDDS_HOME"); + chdir(hddsdir.c_str()); + XString xmlFile = "main_HDDS.xml"; + document = buildDOMDocument(xmlFile,false); + chdir(saved_cwd); + delete [] saved_cwd; +#endif } else { G4cerr << APP_NAME << " - no hdds geometry file specified!" << G4endl; return; } - - int size=100; - char *saved_cwd = new char[size]; - while (getcwd(saved_cwd, size) == 0) - { - delete [] saved_cwd; - saved_cwd = new char[size *= 2]; - } - char *dirpath = new char[hddsFile.size() + 2]; - chdir(dirname(strcpy(dirpath, hddsFile.c_str()))); - DOMDocument* document = buildDOMDocument(xmlFile,false); if (document == 0) { G4cerr << APP_NAME << " - error parsing HDDS document, " << "cannot continue" << G4endl; return; } - chdir(saved_cwd); - delete [] saved_cwd; - delete [] dirpath; DOMNode* docEl; try { @@ -162,7 +172,14 @@ GlueXDetectorConstruction::GlueXDetectorConstruction(G4String hddsFile) return; } - fHddsBuilder.translate(rootEl); + try { + fHddsBuilder.translate(rootEl); + } + catch (const DOMException &e) { + G4cerr << APP_NAME << " - error scanning HDDS document, " + << XString(e.getMessage()) << G4endl; + exit(1); + } XMLPlatformUtils::Terminate(); } @@ -323,7 +340,7 @@ void GlueXDetectorConstruction::ConstructSDandField() } iter->second->SetSensitiveDetector(bcalHandler); } - else if (volname == "LGBL") { + else if (volname == "LGBL" || volname == "LGLG") { if (fcalHandler == 0) { fcalHandler = new GlueXSensitiveDetectorFCAL("fcal"); SDman->AddNewDetector(fcalHandler); @@ -344,20 +361,41 @@ void GlueXDetectorConstruction::ConstructSDandField() } iter->second->SetSensitiveDetector(ccalHandler); } - else if (volname == "FTOC" || volname == "FTOX" || volname == "FTOH") { + else if (volname == "FTOC" || volname == "FTOX" || + volname == "FTOH" || volname == "FTOL") + { if (ftofHandler == 0) { ftofHandler = new GlueXSensitiveDetectorFTOF("ftof"); SDman->AddNewDetector(ftofHandler); } iter->second->SetSensitiveDetector(ftofHandler); } - else if (volname == "QZBL" || volname == "PIXV") { + // radiator volume: BNNM (NN = bar number 0-47 and M is sub-bar character A-D) + else if (volname == "PIXV" || + (volname(0,1)(0) == 'B' && + 10*((int)volname(1,1)(0)-48)+(int)volname(2,1)(0)-48 >= 0 && + 10*((int)volname(1,1)(0)-48)+(int)volname(2,1)(0)-48 < 48)) + { // this is nasty, but it works if (dircHandler == 0) { dircHandler = new GlueXSensitiveDetectorDIRC("dirc"); SDman->AddNewDetector(dircHandler); } iter->second->SetSensitiveDetector(dircHandler); } + else if (volname == "WM1N" || volname == "WM2N" || volname == "WM1S" || volname == "WM2S" || + volname == "FTMN" || volname == "FTMS" || + volname == "TM1N" || volname == "TM2N" || volname == "TM3N" || + volname == "TM1S" || volname == "TM2S" || volname == "TM3S" || + volname == "SM1N" || volname == "SM2N" || volname == "SM1S" || volname == "SM2S" || + volname == "OWDG" || + (volname(0,1)(0) == 'A' && volname(0,1)(1) == 'G') ) + { + if (dircHandler == 0) { + dircHandler = new GlueXSensitiveDetectorDIRC("dirc"); + SDman->AddNewDetector(dircHandler); + } + iter->second->SetSensitiveDetector(dircHandler); + } else if (volname == "CERW" || volname == "CPPC") { if (cereHandler == 0) { cereHandler = new GlueXSensitiveDetectorCERE("cere"); @@ -430,8 +468,13 @@ void GlueXDetectorConstruction::CloneF() // First time we see this FM, let's clone and remember... G4ChordFinder *cfinder = masterFM->GetChordFinder(); +#if G4VERSION_10_04_OR_LATER + G4VIntegrationDriver *midriver = cfinder->GetIntegrationDriver(); + double stepMinimum = 1e-2; +#else G4MagInt_Driver *midriver = cfinder->GetIntegrationDriver(); double stepMinimum = midriver->GetHmin(); +#endif G4MagIntegratorStepper *stepper = midriver->GetStepper(); const G4Field *field = masterFM->GetDetectorField(); @@ -508,7 +551,7 @@ int GlueXDetectorConstruction::GetParallelWorldCount() const G4String GlueXDetectorConstruction::GetParallelWorldName(int paraIndex) const { std::stringstream worldStr; - worldStr << "Parallel World " << paraIndex; + worldStr << "ParallelWorld" << paraIndex; return worldStr.str(); } diff --git a/src/GlueXDetectorConstruction.hh b/src/GlueXDetectorConstruction.hh index 9c45723..5d4f82f 100644 --- a/src/GlueXDetectorConstruction.hh +++ b/src/GlueXDetectorConstruction.hh @@ -21,6 +21,7 @@ #include #include #include +#include class G4Box; class G4LogicalVolume; @@ -70,6 +71,9 @@ class GlueXDetectorConstruction : public G4VUserDetectorConstruction static G4Mutex fMutex; static std::list fInstance; + + protected: + HddsGeometryXML *fGeometryXML; }; class GlueXParallelWorld : public G4VUserParallelWorld diff --git a/src/GlueXHitBCALcell.cc b/src/GlueXHitBCALcell.cc index e25fa3f..5a7c2d8 100644 --- a/src/GlueXHitBCALcell.cc +++ b/src/GlueXHitBCALcell.cc @@ -15,6 +15,14 @@ GlueXHitBCALcell::GlueXHitBCALcell(G4int module, G4int layer, G4int sector) sector_(sector) {} +GlueXHitBCALcell::GlueXHitBCALcell(const GlueXHitBCALcell &src) +{ + module_ = src.module_; + layer_ = src.layer_; + sector_ = src.sector_; + hits = src.hits; +} + int GlueXHitBCALcell::operator==(const GlueXHitBCALcell &right) const { if (module_ != right.module_ || layer_ != right.layer_ || @@ -30,6 +38,10 @@ int GlueXHitBCALcell::operator==(const GlueXHitBCALcell &right) const if (hits[ih].E_GeV != right.hits[ih].E_GeV || hits[ih].zlocal_cm != right.hits[ih].zlocal_cm || hits[ih].t_ns != right.hits[ih].t_ns || + hits[ih].Eup_GeV != right.hits[ih].Eup_GeV || + hits[ih].Edown_GeV != right.hits[ih].Edown_GeV || + hits[ih].tup_ns != right.hits[ih].tup_ns || + hits[ih].tdown_ns != right.hits[ih].tdown_ns || hits[ih].incidentId_ != right.hits[ih].incidentId_ ) { return 0; @@ -74,9 +86,13 @@ void GlueXHitBCALcell::Print() const std::vector::const_iterator hiter; for (hiter = hits.begin(); hiter != hits.end(); ++hiter) { G4cout << " E = " << hiter->E_GeV << " GeV" << G4endl - << " zlocal = " << hiter->t_ns << " cm" << G4endl << " t = " << hiter->t_ns << " ns" << G4endl + << " zlocal = " << hiter->t_ns << " cm" << G4endl << " incidentId = " << hiter->incidentId_ << G4endl + << " E(upstream end) = " << hiter->Eup_GeV << " GeV" << G4endl + << " E(downstream end) = " << hiter->Edown_GeV << " GeV" << G4endl + << " t(upstream end) = " << hiter->tup_ns << " ns" << G4endl + << " t(downstream end) = " << hiter->tdown_ns << " ns" << G4endl << G4endl; } } diff --git a/src/GlueXHitBCALcell.hh b/src/GlueXHitBCALcell.hh index 8869681..4549836 100644 --- a/src/GlueXHitBCALcell.hh +++ b/src/GlueXHitBCALcell.hh @@ -19,7 +19,9 @@ class GlueXHitBCALcell : public G4VHit { public: + GlueXHitBCALcell() {} GlueXHitBCALcell(G4int module, G4int layer, G4int sector); + GlueXHitBCALcell(const GlueXHitBCALcell &src); int operator==(const GlueXHitBCALcell &right) const; GlueXHitBCALcell &operator+=(const GlueXHitBCALcell &right); @@ -40,6 +42,10 @@ class GlueXHitBCALcell : public G4VHit G4double t_ns; // pulse leading-edge time (ns) G4double zlocal_cm; // z coordinate of the hit in local refsys G4double incidentId_; // id of particle that generated this shower + G4double Eup_GeV; // upstream end energy deposition (GeV) + G4double Edown_GeV; // downstream end energy deposition (GeV) + G4double tup_ns; // upstream end pulse leading-edge time (ns) + G4double tdown_ns; // downstream end pulse leading-edge time (ns) }; std::vector hits; diff --git a/src/GlueXHitBCALpoint.cc b/src/GlueXHitBCALpoint.cc index 675abbe..94a3116 100644 --- a/src/GlueXHitBCALpoint.cc +++ b/src/GlueXHitBCALpoint.cc @@ -8,6 +8,22 @@ G4ThreadLocal G4Allocator* GlueXHitBCALpointAllocator = 0; +GlueXHitBCALpoint::GlueXHitBCALpoint(const GlueXHitBCALpoint &src) +{ + E_GeV = src.E_GeV; + phi_rad = src.phi_rad; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + r_cm = src.r_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitBCALpoint::operator==(const GlueXHitBCALpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitBCALpoint.hh b/src/GlueXHitBCALpoint.hh index 1e4b7c9..4913783 100644 --- a/src/GlueXHitBCALpoint.hh +++ b/src/GlueXHitBCALpoint.hh @@ -20,6 +20,7 @@ class GlueXHitBCALpoint : public G4VHit { public: GlueXHitBCALpoint() {} + GlueXHitBCALpoint(const GlueXHitBCALpoint &src); int operator==(const GlueXHitBCALpoint &right) const; GlueXHitBCALpoint &operator+=(const GlueXHitBCALpoint &right); diff --git a/src/GlueXHitCCALblock.cc b/src/GlueXHitCCALblock.cc index c8a6501..d8f2e9b 100644 --- a/src/GlueXHitCCALblock.cc +++ b/src/GlueXHitCCALblock.cc @@ -14,6 +14,13 @@ GlueXHitCCALblock::GlueXHitCCALblock(G4int column, G4int row) row_(row) {} +GlueXHitCCALblock::GlueXHitCCALblock(const GlueXHitCCALblock &src) +{ + column_ = src.column_; + row_ = src.row_; + hits = src.hits; +} + int GlueXHitCCALblock::operator==(const GlueXHitCCALblock &right) const { if (column_ != right.column_ || row_ != right.row_) { diff --git a/src/GlueXHitCCALblock.hh b/src/GlueXHitCCALblock.hh index 8b0db9d..f1a95e9 100644 --- a/src/GlueXHitCCALblock.hh +++ b/src/GlueXHitCCALblock.hh @@ -19,7 +19,9 @@ class GlueXHitCCALblock : public G4VHit { public: + GlueXHitCCALblock() {} GlueXHitCCALblock(G4int column, G4int row); + GlueXHitCCALblock(const GlueXHitCCALblock &src); int operator==(const GlueXHitCCALblock &right) const; GlueXHitCCALblock &operator+=(const GlueXHitCCALblock &right); diff --git a/src/GlueXHitCCALpoint.cc b/src/GlueXHitCCALpoint.cc index a8005af..dc5e430 100644 --- a/src/GlueXHitCCALpoint.cc +++ b/src/GlueXHitCCALpoint.cc @@ -8,6 +8,22 @@ G4ThreadLocal G4Allocator* GlueXHitCCALpointAllocator = 0; +GlueXHitCCALpoint::GlueXHitCCALpoint(const GlueXHitCCALpoint &src) +{ + E_GeV = src.E_GeV; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitCCALpoint::operator==(const GlueXHitCCALpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitCCALpoint.hh b/src/GlueXHitCCALpoint.hh index 5ad0397..a22f235 100644 --- a/src/GlueXHitCCALpoint.hh +++ b/src/GlueXHitCCALpoint.hh @@ -20,6 +20,7 @@ class GlueXHitCCALpoint : public G4VHit { public: GlueXHitCCALpoint() {} + GlueXHitCCALpoint(const GlueXHitCCALpoint &src); int operator==(const GlueXHitCCALpoint &right) const; GlueXHitCCALpoint &operator+=(const GlueXHitCCALpoint &right); diff --git a/src/GlueXHitCDCpoint.cc b/src/GlueXHitCDCpoint.cc index 594b348..c218417 100644 --- a/src/GlueXHitCDCpoint.cc +++ b/src/GlueXHitCDCpoint.cc @@ -8,6 +8,25 @@ G4ThreadLocal G4Allocator* GlueXHitCDCpointAllocator = 0; +GlueXHitCDCpoint::GlueXHitCDCpoint(const GlueXHitCDCpoint &src) +{ + dEdx_GeV_cm = src.dEdx_GeV_cm; + dradius_cm = src.dradius_cm; + phi_rad = src.phi_rad; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + r_cm = src.r_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; + sector_ = src.sector_; + ring_ = src.ring_; +} + int GlueXHitCDCpoint::operator==(const GlueXHitCDCpoint &right) const { if (dEdx_GeV_cm != right.dEdx_GeV_cm || diff --git a/src/GlueXHitCDCpoint.hh b/src/GlueXHitCDCpoint.hh index a44edbd..9594f54 100644 --- a/src/GlueXHitCDCpoint.hh +++ b/src/GlueXHitCDCpoint.hh @@ -20,6 +20,7 @@ class GlueXHitCDCpoint : public G4VHit { public: GlueXHitCDCpoint() {} + GlueXHitCDCpoint(const GlueXHitCDCpoint &src); int operator==(const GlueXHitCDCpoint &right) const; GlueXHitCDCpoint &operator+=(const GlueXHitCDCpoint &right); diff --git a/src/GlueXHitCDCstraw.cc b/src/GlueXHitCDCstraw.cc index 35fc036..a75921f 100644 --- a/src/GlueXHitCDCstraw.cc +++ b/src/GlueXHitCDCstraw.cc @@ -15,6 +15,13 @@ GlueXHitCDCstraw::GlueXHitCDCstraw(G4int ring, G4int sector) sector_(sector) {} +GlueXHitCDCstraw::GlueXHitCDCstraw(const GlueXHitCDCstraw &src) +{ + ring_ = src.ring_; + sector_ = src.sector_; + hits = src.hits; +} + int GlueXHitCDCstraw::operator==(const GlueXHitCDCstraw &right) const { if (ring_ != right.ring_ || sector_ != right.sector_) diff --git a/src/GlueXHitCDCstraw.hh b/src/GlueXHitCDCstraw.hh index bb1857f..80cc648 100644 --- a/src/GlueXHitCDCstraw.hh +++ b/src/GlueXHitCDCstraw.hh @@ -20,7 +20,9 @@ class GlueXHitCDCstraw : public G4VHit { public: + GlueXHitCDCstraw() {} GlueXHitCDCstraw(G4int ring, G4int sector); + GlueXHitCDCstraw(const GlueXHitCDCstraw &src); int operator==(const GlueXHitCDCstraw &right) const; GlueXHitCDCstraw &operator+=(const GlueXHitCDCstraw &right); diff --git a/src/GlueXHitCEREpoint.cc b/src/GlueXHitCEREpoint.cc index 5977cc0..c8289bc 100644 --- a/src/GlueXHitCEREpoint.cc +++ b/src/GlueXHitCEREpoint.cc @@ -8,6 +8,22 @@ G4ThreadLocal G4Allocator* GlueXHitCEREpointAllocator = 0; +GlueXHitCEREpoint::GlueXHitCEREpoint(const GlueXHitCEREpoint &src) +{ + E_GeV = src.E_GeV; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitCEREpoint::operator==(const GlueXHitCEREpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitCEREpoint.hh b/src/GlueXHitCEREpoint.hh index abf1ea8..14c1205 100644 --- a/src/GlueXHitCEREpoint.hh +++ b/src/GlueXHitCEREpoint.hh @@ -20,6 +20,7 @@ class GlueXHitCEREpoint : public G4VHit { public: GlueXHitCEREpoint() {} + GlueXHitCEREpoint(const GlueXHitCEREpoint &src); int operator==(const GlueXHitCEREpoint &right) const; GlueXHitCEREpoint &operator+=(const GlueXHitCEREpoint &right); diff --git a/src/GlueXHitCEREtube.cc b/src/GlueXHitCEREtube.cc index 8a6ecc2..c90be87 100644 --- a/src/GlueXHitCEREtube.cc +++ b/src/GlueXHitCEREtube.cc @@ -13,6 +13,12 @@ GlueXHitCEREtube::GlueXHitCEREtube(G4int sector) sector_(sector) {} +GlueXHitCEREtube::GlueXHitCEREtube(const GlueXHitCEREtube &src) +{ + sector_ = src.sector_; + hits = src.hits; +} + int GlueXHitCEREtube::operator==(const GlueXHitCEREtube &right) const { if (sector_ != right.sector_) diff --git a/src/GlueXHitCEREtube.hh b/src/GlueXHitCEREtube.hh index f0f15bf..687a19b 100644 --- a/src/GlueXHitCEREtube.hh +++ b/src/GlueXHitCEREtube.hh @@ -19,7 +19,9 @@ class GlueXHitCEREtube : public G4VHit { public: + GlueXHitCEREtube() {} GlueXHitCEREtube(G4int sector); + GlueXHitCEREtube(const GlueXHitCEREtube &src); int operator==(const GlueXHitCEREtube &right) const; GlueXHitCEREtube &operator+=(const GlueXHitCEREtube &right); diff --git a/src/GlueXHitDIRCBar.cc b/src/GlueXHitDIRCBar.cc index f8372d7..296f685 100644 --- a/src/GlueXHitDIRCBar.cc +++ b/src/GlueXHitDIRCBar.cc @@ -8,8 +8,19 @@ G4ThreadLocal G4Allocator* GlueXHitDIRCBarAllocator = 0; -GlueXHitDIRCBar::GlueXHitDIRCBar():G4VHit() +GlueXHitDIRCBar::GlueXHitDIRCBar(const GlueXHitDIRCBar &src) { + E_GeV = src.E_GeV; + t_ns = src.t_ns; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + pdg = src.pdg; + bar = src.bar; + track = src.track; } void GlueXHitDIRCBar::Draw() const diff --git a/src/GlueXHitDIRCBar.hh b/src/GlueXHitDIRCBar.hh index 34e4704..84a287f 100644 --- a/src/GlueXHitDIRCBar.hh +++ b/src/GlueXHitDIRCBar.hh @@ -14,7 +14,8 @@ class GlueXHitDIRCBar : public G4VHit { public: - GlueXHitDIRCBar(); + GlueXHitDIRCBar() {} + GlueXHitDIRCBar(const GlueXHitDIRCBar &src); void *operator new(size_t); void operator delete(void *aHit); diff --git a/src/GlueXHitDIRCPmt.cc b/src/GlueXHitDIRCPmt.cc index 3e87cb0..7ac4878 100644 --- a/src/GlueXHitDIRCPmt.cc +++ b/src/GlueXHitDIRCPmt.cc @@ -9,9 +9,20 @@ G4ThreadLocal G4Allocator* GlueXHitDIRCPmtAllocator = 0; -GlueXHitDIRCPmt::GlueXHitDIRCPmt() - : G4VHit() -{} +GlueXHitDIRCPmt::GlueXHitDIRCPmt(const GlueXHitDIRCPmt &src) +{ + E_GeV = src.E_GeV; + t_ns = src.t_ns; + t_fixed_ns = src.t_fixed_ns; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + ch = src.ch; + key_bar = src.key_bar; + path = src.path; + refl = src.refl; + bbrefl = src.bbrefl; +} void GlueXHitDIRCPmt::Draw() const { @@ -22,9 +33,13 @@ void GlueXHitDIRCPmt::Print() const { G4cout << " E = " << E_GeV << " GeV" << G4endl << " t = " << t_ns << " ns" << G4endl + << " t_fixed = " << t_fixed_ns << " ns" << G4endl << " x = " << x_cm << " cm" << G4endl << " y = " << y_cm << " cm" << G4endl << " z = " << z_cm << " cm" << G4endl + << " path = " << path << " " << G4endl + << " refl = " << refl << " " << G4endl + << " bbrefl = " << bbrefl << " " << G4endl << " ch = " << ch << " " << G4endl << " key_bar = " << key_bar << " " << G4endl << G4endl; diff --git a/src/GlueXHitDIRCPmt.hh b/src/GlueXHitDIRCPmt.hh index 5787b0c..afd9c47 100644 --- a/src/GlueXHitDIRCPmt.hh +++ b/src/GlueXHitDIRCPmt.hh @@ -14,7 +14,8 @@ class GlueXHitDIRCPmt : public G4VHit { public: - GlueXHitDIRCPmt(); + GlueXHitDIRCPmt() {} + GlueXHitDIRCPmt(const GlueXHitDIRCPmt &src); void *operator new(size_t); void operator delete(void *aHit); @@ -24,12 +25,16 @@ public: G4double E_GeV; // photon energy [GeV] G4double t_ns; // detection time [ns] + G4double t_fixed_ns; // fixed pathlength time [ns] G4double x_cm; // x coordinate where hit was created G4double y_cm; // y coordinate where hit was created G4double z_cm; // z coordinate where hit was created + int64_t path; // photon's path id in the optical box + G4int refl; // number of reflections in the oprical box + G4bool bbrefl; // reflected off far end mirror of bar box G4int ch; // PMT channel of the hit G4int key_bar; // key of the corresponding bar hit - + G4int track; // index of the MC track }; typedef G4THitsMap GlueXHitsMapDIRCPmt; diff --git a/src/GlueXHitDIRCWob.cc b/src/GlueXHitDIRCWob.cc new file mode 100644 index 0000000..2269660 --- /dev/null +++ b/src/GlueXHitDIRCWob.cc @@ -0,0 +1,26 @@ +// +// GlueXHitDIRCWob - class implementation +// +// created on: 05.04.2017 +// original author: r.dzhygadlo at gsi.de + +#include "GlueXHitDIRCWob.hh" + +G4ThreadLocal G4Allocator* GlueXHitDIRCWobAllocator = 0; + +GlueXHitDIRCWob::GlueXHitDIRCWob():G4VHit() +{ +} + +void GlueXHitDIRCWob::Draw() const +{ + // not yet implemented +} + +void GlueXHitDIRCWob::Print() const +{ + G4cout << "GlueXHitDIRCWob:" << G4endl + << " track = " << track << G4endl + << " normalId = " << normalId << " " << G4endl + << G4endl; +} diff --git a/src/GlueXHitDIRCWob.hh b/src/GlueXHitDIRCWob.hh new file mode 100644 index 0000000..3e71bea --- /dev/null +++ b/src/GlueXHitDIRCWob.hh @@ -0,0 +1,45 @@ +// +// GlueXHitDIRCWob - class implementation +// +// created on: 05.04.2017 +// original author: r.dzhygadlo at gsi.de + +#ifndef GlueXHitDIRCWob_h +#define GlueXHitDIRCWob_h 1 + +#include "G4VHit.hh" +#include "G4THitsMap.hh" +#include "G4Allocator.hh" + +class GlueXHitDIRCWob : public G4VHit +{ +public: + GlueXHitDIRCWob(); + + void *operator new(size_t); + void operator delete(void *aHit); + + void Draw() const; + void Print() const; + + G4double normalId; // uniq identifier of the normal + G4int track; // index of the MC track +}; + +typedef G4THitsMap GlueXHitsMapDIRCWob; + +extern G4ThreadLocal G4Allocator* GlueXHitDIRCWobAllocator; + +inline void* GlueXHitDIRCWob::operator new(size_t) +{ + if (!GlueXHitDIRCWobAllocator) + GlueXHitDIRCWobAllocator = new G4Allocator; + return (void *) GlueXHitDIRCWobAllocator->MallocSingle(); +} + +inline void GlueXHitDIRCWob::operator delete(void *aHit) +{ + GlueXHitDIRCWobAllocator->FreeSingle((GlueXHitDIRCWob*) aHit); +} + +#endif diff --git a/src/GlueXHitDIRCflash.cc b/src/GlueXHitDIRCflash.cc index 355243e..8991c6b 100644 --- a/src/GlueXHitDIRCflash.cc +++ b/src/GlueXHitDIRCflash.cc @@ -26,6 +26,12 @@ GlueXHitDIRCflash::GlueXHitDIRCflash(G4int bar) bar_(bar) {} +GlueXHitDIRCflash::GlueXHitDIRCflash(const GlueXHitDIRCflash &src) +{ + bar_ = src.bar_; + hits = src.hits; +} + int GlueXHitDIRCflash::operator==(const GlueXHitDIRCflash &right) const { if (bar_ != right.bar_) diff --git a/src/GlueXHitDIRCflash.hh b/src/GlueXHitDIRCflash.hh index e2f13eb..321f14a 100644 --- a/src/GlueXHitDIRCflash.hh +++ b/src/GlueXHitDIRCflash.hh @@ -33,6 +33,7 @@ class GlueXHitDIRCflash : public G4VHit { public: GlueXHitDIRCflash(G4int bar=0); + GlueXHitDIRCflash(const GlueXHitDIRCflash &src); int operator==(const GlueXHitDIRCflash &right) const; GlueXHitDIRCflash &operator+=(const GlueXHitDIRCflash &right); diff --git a/src/GlueXHitDIRCpoint.cc b/src/GlueXHitDIRCpoint.cc deleted file mode 100644 index 5b9679e..0000000 --- a/src/GlueXHitDIRCpoint.cc +++ /dev/null @@ -1,72 +0,0 @@ -// -// GlueXHitDIRCpoint - class implementation -// -// author: richard.t.jones at uconn.edu -// version: november 26, 2016 - -#include "GlueXHitDIRCpoint.hh" - -G4ThreadLocal G4Allocator* GlueXHitDIRCpointAllocator = 0; - -int GlueXHitDIRCpoint::operator==(const GlueXHitDIRCpoint &right) const -{ - if (E_GeV != right.E_GeV || - primary_ != right.primary_ || - ptype_G3 != right.ptype_G3 || - px_GeV != right.px_GeV || - py_GeV != right.py_GeV || - pz_GeV != right.pz_GeV || - x_cm != right.x_cm || - y_cm != right.y_cm || - z_cm != right.z_cm || - t_ns != right.t_ns || - track_ != right.track_ || - trackID_ != right.trackID_ ) - { - return 0; - } - return 1; -} - -GlueXHitDIRCpoint &GlueXHitDIRCpoint::operator+=(const GlueXHitDIRCpoint &right) -{ - G4cerr << "Error in GlueXHitDIRCpoint::operator+= - " - << "illegal attempt to merge two TruthPoint objects in the DIRC!" - << G4endl; - return *this; -} - -void GlueXHitDIRCpoint::Draw() const -{ - // not yet implemented -} - -void GlueXHitDIRCpoint::Print() const -{ - G4cout << "GlueXHitDIRCpoint:" << G4endl - << " track = " << track_ << G4endl - << " trackID = " << trackID_ << G4endl - << " E = " << E_GeV << " GeV" << G4endl - << " primary = " << primary_ << G4endl - << " ptype = " << ptype_G3 << G4endl - << " px = " << px_GeV << " GeV/c" << G4endl - << " py = " << py_GeV << " GeV/c" << G4endl - << " pz = " << pz_GeV << " GeV/c" << G4endl - << " x = " << x_cm << " cm" << G4endl - << " y = " << y_cm << " cm" << G4endl - << " z = " << z_cm << " cm" << G4endl - << " t = " << t_ns << " ns" << G4endl - << G4endl; -} - -void printallhits(GlueXHitsMapDIRCpoint *hitsmap) -{ - std::map *map = hitsmap->GetMap(); - std::map::const_iterator iter; - G4cout << "G4THitsMap " << hitsmap->GetName() << " with " << hitsmap->entries() - << " entries:" << G4endl; - for (iter = map->begin(); iter != map->end(); ++iter) { - G4cout << " key=" << iter->first << " "; - iter->second->Print(); - } -} diff --git a/src/GlueXHitDIRCpoint.hh b/src/GlueXHitDIRCpoint.hh deleted file mode 100644 index 0adbb15..0000000 --- a/src/GlueXHitDIRCpoint.hh +++ /dev/null @@ -1,66 +0,0 @@ -// -// GlueXHitDIRCpoint - class header -// -// author: richard.t.jones at uconn.edu -// version: november 26, 2016 -// -// In the context of the Geant4 event-level multithreading model, -// this class is "thread-local", ie. has thread-local state. Its -// allocator is designed to run within a worker thread context. -// This class is final, do NOT try to derive another class from it. - -#ifndef GlueXHitDIRCpoint_h -#define GlueXHitDIRCpoint_h 1 - -#include "G4VHit.hh" -#include "G4THitsMap.hh" -#include "G4Allocator.hh" - -class GlueXHitDIRCpoint : public G4VHit -{ - public: - GlueXHitDIRCpoint() {} - int operator==(const GlueXHitDIRCpoint &right) const; - GlueXHitDIRCpoint &operator+=(const GlueXHitDIRCpoint &right); - - void *operator new(size_t); - void operator delete(void *aHit); - - void Draw() const; - void Print() const; - - // no reason to hide hit data - - G4double E_GeV; // total energy (GeV) of this track at this point - G4bool primary_; // true if track belongs to from a primary particle - G4int ptype_G3; // G3 type of particle making this track - G4double px_GeV; // momentum (GeV/c) of track at point, x component - G4double py_GeV; // momentum (GeV/c) of track at point, y component - G4double pz_GeV; // momentum (GeV/c) of track at point, z component - G4double x_cm; // global x coordinate of track at point (cm) - G4double y_cm; // global y coordinate of track at point (cm) - G4double z_cm; // global z coordinate of track at point (cm) - G4double t_ns; // time of track crossing at point (ns) - G4int track_; // Geant4 track ID of particle making this track - G4int trackID_; // GlueX-assigned track ID of particle making this track - - G4int GetKey() const { return (track_ << 20) + int(t_ns * 100); } -}; - -typedef G4THitsMap GlueXHitsMapDIRCpoint; - -extern G4ThreadLocal G4Allocator* GlueXHitDIRCpointAllocator; - -inline void* GlueXHitDIRCpoint::operator new(size_t) -{ - if (!GlueXHitDIRCpointAllocator) - GlueXHitDIRCpointAllocator = new G4Allocator; - return (void *) GlueXHitDIRCpointAllocator->MallocSingle(); -} - -inline void GlueXHitDIRCpoint::operator delete(void *aHit) -{ - GlueXHitDIRCpointAllocator->FreeSingle((GlueXHitDIRCpoint*) aHit); -} - -#endif diff --git a/src/GlueXHitFCALblock.cc b/src/GlueXHitFCALblock.cc index f997006..98c44e1 100644 --- a/src/GlueXHitFCALblock.cc +++ b/src/GlueXHitFCALblock.cc @@ -14,6 +14,13 @@ GlueXHitFCALblock::GlueXHitFCALblock(G4int column, G4int row) row_(row) {} +GlueXHitFCALblock::GlueXHitFCALblock(const GlueXHitFCALblock &src) +{ + column_ = src.column_; + row_ = src.row_; + hits = src.hits; +} + int GlueXHitFCALblock::operator==(const GlueXHitFCALblock &right) const { if (column_ != right.column_ || row_ != right.row_) { @@ -25,7 +32,9 @@ int GlueXHitFCALblock::operator==(const GlueXHitFCALblock &right) const for (int ih=0; ih < (int)hits.size(); ++ih) { if (hits[ih].E_GeV != right.hits[ih].E_GeV || - hits[ih].t_ns != right.hits[ih].t_ns) + hits[ih].t_ns != right.hits[ih].t_ns || + hits[ih].dE_lightguide_GeV != right.hits[ih].dE_lightguide_GeV || + hits[ih].t_lightguide_ns != right.hits[ih].t_lightguide_ns) { return 0; } @@ -67,6 +76,10 @@ void GlueXHitFCALblock::Print() const for (hiter = hits.begin(); hiter != hits.end(); ++hiter) { G4cout << " E = " << hiter->E_GeV << " GeV" << G4endl << " t = " << hiter->t_ns << " ns" << G4endl + << " E(lightguide) = " + << hiter->dE_lightguide_GeV << " GeV" << G4endl + << " t(lightguide) = " + << hiter->t_lightguide_ns << " ns" << G4endl << G4endl; } } diff --git a/src/GlueXHitFCALblock.hh b/src/GlueXHitFCALblock.hh index e4617e2..08a3c3e 100644 --- a/src/GlueXHitFCALblock.hh +++ b/src/GlueXHitFCALblock.hh @@ -19,7 +19,9 @@ class GlueXHitFCALblock : public G4VHit { public: + GlueXHitFCALblock() {} GlueXHitFCALblock(G4int column, G4int row); + GlueXHitFCALblock(const GlueXHitFCALblock &src); int operator==(const GlueXHitFCALblock &right) const; GlueXHitFCALblock &operator+=(const GlueXHitFCALblock &right); @@ -37,6 +39,8 @@ class GlueXHitFCALblock : public G4VHit struct hitinfo_t { G4double E_GeV; // energy deposition (GeV) G4double t_ns; // pulse leading-edge time (ns) + G4double dE_lightguide_GeV; // light guide energy deposition (GeV) + G4double t_lightguide_ns; // light guide pulse leading-edge time (ns) }; std::vector hits; diff --git a/src/GlueXHitFCALpoint.cc b/src/GlueXHitFCALpoint.cc index d20047c..d3e0585 100644 --- a/src/GlueXHitFCALpoint.cc +++ b/src/GlueXHitFCALpoint.cc @@ -8,6 +8,22 @@ G4ThreadLocal G4Allocator* GlueXHitFCALpointAllocator = 0; +GlueXHitFCALpoint::GlueXHitFCALpoint(const GlueXHitFCALpoint &src) +{ + E_GeV = src.E_GeV; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitFCALpoint::operator==(const GlueXHitFCALpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitFCALpoint.hh b/src/GlueXHitFCALpoint.hh index a0cc2a6..e7eee9f 100644 --- a/src/GlueXHitFCALpoint.hh +++ b/src/GlueXHitFCALpoint.hh @@ -20,6 +20,7 @@ class GlueXHitFCALpoint : public G4VHit { public: GlueXHitFCALpoint() {} + GlueXHitFCALpoint(const GlueXHitFCALpoint &src); int operator==(const GlueXHitFCALpoint &right) const; GlueXHitFCALpoint &operator+=(const GlueXHitFCALpoint &right); diff --git a/src/GlueXHitFDCcathode.cc b/src/GlueXHitFDCcathode.cc index 8aece62..d8568f2 100644 --- a/src/GlueXHitFDCcathode.cc +++ b/src/GlueXHitFDCcathode.cc @@ -15,6 +15,14 @@ GlueXHitFDCcathode::GlueXHitFDCcathode(G4int chamber, G4int plane, G4int strip) strip_(strip) {} +GlueXHitFDCcathode::GlueXHitFDCcathode(const GlueXHitFDCcathode &src) +{ + chamber_ = src.chamber_; + plane_ = src.plane_; + strip_ = src.strip_; + hits = src.hits; +} + int GlueXHitFDCcathode::operator==(const GlueXHitFDCcathode &right) const { if (chamber_ != right.chamber_ || diff --git a/src/GlueXHitFDCcathode.hh b/src/GlueXHitFDCcathode.hh index 26b9899..12b75da 100644 --- a/src/GlueXHitFDCcathode.hh +++ b/src/GlueXHitFDCcathode.hh @@ -19,7 +19,9 @@ class GlueXHitFDCcathode : public G4VHit { public: + GlueXHitFDCcathode() {} GlueXHitFDCcathode(G4int chamber, G4int plane, G4int strip); + GlueXHitFDCcathode(const GlueXHitFDCcathode &src); int operator==(const GlueXHitFDCcathode &right) const; GlueXHitFDCcathode &operator+=(const GlueXHitFDCcathode &right); diff --git a/src/GlueXHitFDCpoint.cc b/src/GlueXHitFDCpoint.cc index f4a5566..83f5890 100644 --- a/src/GlueXHitFDCpoint.cc +++ b/src/GlueXHitFDCpoint.cc @@ -13,6 +13,25 @@ GlueXHitFDCpoint::GlueXHitFDCpoint(G4int chamber) chamber_(chamber) {} +GlueXHitFDCpoint::GlueXHitFDCpoint(const GlueXHitFDCpoint &src) +{ + chamber_ = src.chamber_; + E_GeV = src.E_GeV; + dEdx_GeV_cm = src.dEdx_GeV_cm; + dradius_cm = src.dradius_cm; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitFDCpoint::operator==(const GlueXHitFDCpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitFDCpoint.hh b/src/GlueXHitFDCpoint.hh index 4f0871d..4ce2456 100644 --- a/src/GlueXHitFDCpoint.hh +++ b/src/GlueXHitFDCpoint.hh @@ -19,7 +19,9 @@ class GlueXHitFDCpoint : public G4VHit { public: + GlueXHitFDCpoint() {} GlueXHitFDCpoint(int chamber); + GlueXHitFDCpoint(const GlueXHitFDCpoint &src); int operator==(const GlueXHitFDCpoint &right) const; GlueXHitFDCpoint &operator+=(const GlueXHitFDCpoint &right); diff --git a/src/GlueXHitFDCwire.cc b/src/GlueXHitFDCwire.cc index 05f03f9..3880a6d 100644 --- a/src/GlueXHitFDCwire.cc +++ b/src/GlueXHitFDCwire.cc @@ -14,6 +14,13 @@ GlueXHitFDCwire::GlueXHitFDCwire(G4int chamber, G4int wire) wire_(wire) {} +GlueXHitFDCwire::GlueXHitFDCwire(const GlueXHitFDCwire &src) +{ + chamber_ = src.chamber_; + wire_ = src.wire_; + hits = src.hits; +} + int GlueXHitFDCwire::operator==(const GlueXHitFDCwire &right) const { if (chamber_ != right.chamber_ || wire_ != right.wire_) diff --git a/src/GlueXHitFDCwire.hh b/src/GlueXHitFDCwire.hh index 0824bc0..3863928 100644 --- a/src/GlueXHitFDCwire.hh +++ b/src/GlueXHitFDCwire.hh @@ -20,7 +20,9 @@ class GlueXHitFDCwire : public G4VHit { public: + GlueXHitFDCwire() {} GlueXHitFDCwire(G4int chamber, G4int wire); + GlueXHitFDCwire(const GlueXHitFDCwire &src); int operator==(const GlueXHitFDCwire &right) const; GlueXHitFDCwire &operator+=(const GlueXHitFDCwire &right); diff --git a/src/GlueXHitFMWPCpoint.cc b/src/GlueXHitFMWPCpoint.cc index 03e1303..adfa9ad 100644 --- a/src/GlueXHitFMWPCpoint.cc +++ b/src/GlueXHitFMWPCpoint.cc @@ -8,6 +8,22 @@ G4ThreadLocal G4Allocator* GlueXHitFMWPCpointAllocator = 0; +GlueXHitFMWPCpoint::GlueXHitFMWPCpoint(const GlueXHitFMWPCpoint &src) +{ + E_GeV = src.E_GeV; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitFMWPCpoint::operator==(const GlueXHitFMWPCpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitFMWPCpoint.hh b/src/GlueXHitFMWPCpoint.hh index 5f553e7..38ad3eb 100644 --- a/src/GlueXHitFMWPCpoint.hh +++ b/src/GlueXHitFMWPCpoint.hh @@ -20,6 +20,7 @@ class GlueXHitFMWPCpoint : public G4VHit { public: GlueXHitFMWPCpoint() {} + GlueXHitFMWPCpoint(const GlueXHitFMWPCpoint &src); int operator==(const GlueXHitFMWPCpoint &right) const; GlueXHitFMWPCpoint &operator+=(const GlueXHitFMWPCpoint &right); diff --git a/src/GlueXHitFMWPCwire.cc b/src/GlueXHitFMWPCwire.cc index 28c0ab7..7963ba5 100644 --- a/src/GlueXHitFMWPCwire.cc +++ b/src/GlueXHitFMWPCwire.cc @@ -14,6 +14,13 @@ GlueXHitFMWPCwire::GlueXHitFMWPCwire(G4int layer, G4int wire) wire_(wire) {} +GlueXHitFMWPCwire::GlueXHitFMWPCwire(const GlueXHitFMWPCwire &src) +{ + layer_ = src.layer_; + wire_ = src.wire_; + hits = src.hits; +} + int GlueXHitFMWPCwire::operator==(const GlueXHitFMWPCwire &right) const { if (layer_ != right.layer_ || wire_ != right.wire_) diff --git a/src/GlueXHitFMWPCwire.hh b/src/GlueXHitFMWPCwire.hh index c9e3c70..779c6e3 100644 --- a/src/GlueXHitFMWPCwire.hh +++ b/src/GlueXHitFMWPCwire.hh @@ -19,7 +19,9 @@ class GlueXHitFMWPCwire : public G4VHit { public: + GlueXHitFMWPCwire() {} GlueXHitFMWPCwire(G4int layer, G4int wire); + GlueXHitFMWPCwire(const GlueXHitFMWPCwire &src); int operator==(const GlueXHitFMWPCwire &right) const; GlueXHitFMWPCwire &operator+=(const GlueXHitFMWPCwire &right); diff --git a/src/GlueXHitFTOFbar.cc b/src/GlueXHitFTOFbar.cc index 2f36a1d..eb55fe5 100644 --- a/src/GlueXHitFTOFbar.cc +++ b/src/GlueXHitFTOFbar.cc @@ -14,6 +14,13 @@ GlueXHitFTOFbar::GlueXHitFTOFbar(G4int plane, G4int bar) bar_(bar) {} +GlueXHitFTOFbar::GlueXHitFTOFbar(const GlueXHitFTOFbar &src) +{ + plane_ = src.plane_; + bar_ = src.bar_; + hits = src.hits; +} + int GlueXHitFTOFbar::operator==(const GlueXHitFTOFbar &right) const { if (plane_ != right.plane_ || bar_ != right.bar_ ) diff --git a/src/GlueXHitFTOFbar.hh b/src/GlueXHitFTOFbar.hh index a33c5cc..d3633cd 100644 --- a/src/GlueXHitFTOFbar.hh +++ b/src/GlueXHitFTOFbar.hh @@ -19,7 +19,9 @@ class GlueXHitFTOFbar : public G4VHit { public: + GlueXHitFTOFbar() {} GlueXHitFTOFbar(G4int plane, G4int bar); + GlueXHitFTOFbar(const GlueXHitFTOFbar &src); int operator==(const GlueXHitFTOFbar &right) const; GlueXHitFTOFbar &operator+=(const GlueXHitFTOFbar &right); diff --git a/src/GlueXHitFTOFpoint.cc b/src/GlueXHitFTOFpoint.cc index dccfd9b..3dccbcd 100644 --- a/src/GlueXHitFTOFpoint.cc +++ b/src/GlueXHitFTOFpoint.cc @@ -8,6 +8,22 @@ G4ThreadLocal G4Allocator* GlueXHitFTOFpointAllocator = 0; +GlueXHitFTOFpoint::GlueXHitFTOFpoint(const GlueXHitFTOFpoint &src) +{ + E_GeV = src.E_GeV; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitFTOFpoint::operator==(const GlueXHitFTOFpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitFTOFpoint.hh b/src/GlueXHitFTOFpoint.hh index 51bd9db..58b57ff 100644 --- a/src/GlueXHitFTOFpoint.hh +++ b/src/GlueXHitFTOFpoint.hh @@ -20,6 +20,7 @@ class GlueXHitFTOFpoint : public G4VHit { public: GlueXHitFTOFpoint() {} + GlueXHitFTOFpoint(const GlueXHitFTOFpoint &src); int operator==(const GlueXHitFTOFpoint &right) const; GlueXHitFTOFpoint &operator+=(const GlueXHitFTOFpoint &right); diff --git a/src/GlueXHitGCALblock.cc b/src/GlueXHitGCALblock.cc index c19dd28..dddc816 100644 --- a/src/GlueXHitGCALblock.cc +++ b/src/GlueXHitGCALblock.cc @@ -13,6 +13,12 @@ GlueXHitGCALblock::GlueXHitGCALblock(G4int module) module_(module) {} +GlueXHitGCALblock::GlueXHitGCALblock(const GlueXHitGCALblock &src) +{ + module_ = src.module_; + hits = src.hits; +} + int GlueXHitGCALblock::operator==(const GlueXHitGCALblock &right) const { if (module_ != right.module_) { diff --git a/src/GlueXHitGCALblock.hh b/src/GlueXHitGCALblock.hh index ee481b1..eb3775f 100644 --- a/src/GlueXHitGCALblock.hh +++ b/src/GlueXHitGCALblock.hh @@ -19,7 +19,9 @@ class GlueXHitGCALblock : public G4VHit { public: + GlueXHitGCALblock() {} GlueXHitGCALblock(G4int module); + GlueXHitGCALblock(const GlueXHitGCALblock &src); int operator==(const GlueXHitGCALblock &right) const; GlueXHitGCALblock &operator+=(const GlueXHitGCALblock &right); diff --git a/src/GlueXHitGCALpoint.cc b/src/GlueXHitGCALpoint.cc index 66a112c..4838e0f 100644 --- a/src/GlueXHitGCALpoint.cc +++ b/src/GlueXHitGCALpoint.cc @@ -8,6 +8,22 @@ G4ThreadLocal G4Allocator* GlueXHitGCALpointAllocator = 0; +GlueXHitGCALpoint::GlueXHitGCALpoint(const GlueXHitGCALpoint &src) +{ + E_GeV = src.E_GeV; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + r_cm = src.r_cm; + phi_rad = src.phi_rad; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitGCALpoint::operator==(const GlueXHitGCALpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitGCALpoint.hh b/src/GlueXHitGCALpoint.hh index e1d5f07..0981b3e 100644 --- a/src/GlueXHitGCALpoint.hh +++ b/src/GlueXHitGCALpoint.hh @@ -20,6 +20,7 @@ class GlueXHitGCALpoint : public G4VHit { public: GlueXHitGCALpoint() {} + GlueXHitGCALpoint(const GlueXHitGCALpoint &src); int operator==(const GlueXHitGCALpoint &right) const; GlueXHitGCALpoint &operator+=(const GlueXHitGCALpoint &right); diff --git a/src/GlueXHitPSCpaddle.cc b/src/GlueXHitPSCpaddle.cc index f852c4c..8e5a8b0 100644 --- a/src/GlueXHitPSCpaddle.cc +++ b/src/GlueXHitPSCpaddle.cc @@ -14,6 +14,13 @@ GlueXHitPSCpaddle::GlueXHitPSCpaddle(G4int arm, G4int module) module_(module) {} +GlueXHitPSCpaddle::GlueXHitPSCpaddle(const GlueXHitPSCpaddle &src) +{ + arm_ = src.arm_; + module_ = src.module_; + hits = src.hits; +} + int GlueXHitPSCpaddle::operator==(const GlueXHitPSCpaddle &right) const { if (module_ != right.module_ || arm_ != right.arm_) diff --git a/src/GlueXHitPSCpaddle.hh b/src/GlueXHitPSCpaddle.hh index 57a8e19..e300cf6 100644 --- a/src/GlueXHitPSCpaddle.hh +++ b/src/GlueXHitPSCpaddle.hh @@ -19,7 +19,9 @@ class GlueXHitPSCpaddle : public G4VHit { public: + GlueXHitPSCpaddle() {} GlueXHitPSCpaddle(G4int arm, G4int module); + GlueXHitPSCpaddle(const GlueXHitPSCpaddle &src); int operator==(const GlueXHitPSCpaddle &right) const; GlueXHitPSCpaddle &operator+=(const GlueXHitPSCpaddle &right); diff --git a/src/GlueXHitPSCpoint.cc b/src/GlueXHitPSCpoint.cc index 0fa6a50..8654e1c 100644 --- a/src/GlueXHitPSCpoint.cc +++ b/src/GlueXHitPSCpoint.cc @@ -8,6 +8,25 @@ G4ThreadLocal G4Allocator* GlueXHitPSCpointAllocator = 0; +GlueXHitPSCpoint::GlueXHitPSCpoint(const GlueXHitPSCpoint &src) +{ + arm_ = src.arm_; + module_ = src.module_; + E_GeV = src.E_GeV; + dEdx_GeV_cm = src.dEdx_GeV_cm; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitPSCpoint::operator==(const GlueXHitPSCpoint &right) const { if (arm_ != right.arm_ || diff --git a/src/GlueXHitPSCpoint.hh b/src/GlueXHitPSCpoint.hh index bb6e817..aa62150 100644 --- a/src/GlueXHitPSCpoint.hh +++ b/src/GlueXHitPSCpoint.hh @@ -20,6 +20,7 @@ class GlueXHitPSCpoint : public G4VHit { public: GlueXHitPSCpoint() {} + GlueXHitPSCpoint(const GlueXHitPSCpoint &src); int operator==(const GlueXHitPSCpoint &right) const; GlueXHitPSCpoint &operator+=(const GlueXHitPSCpoint &right); diff --git a/src/GlueXHitPSpoint.cc b/src/GlueXHitPSpoint.cc index 4ad7172..074425a 100644 --- a/src/GlueXHitPSpoint.cc +++ b/src/GlueXHitPSpoint.cc @@ -8,6 +8,25 @@ G4ThreadLocal G4Allocator* GlueXHitPSpointAllocator = 0; +GlueXHitPSpoint::GlueXHitPSpoint(const GlueXHitPSpoint &src) +{ + arm_ = src.arm_; + column_ = src.column_; + E_GeV = src.E_GeV; + dEdx_GeV_cm = src.dEdx_GeV_cm; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitPSpoint::operator==(const GlueXHitPSpoint &right) const { if (arm_ != right.arm_ || diff --git a/src/GlueXHitPSpoint.hh b/src/GlueXHitPSpoint.hh index 548d7c4..fa86305 100644 --- a/src/GlueXHitPSpoint.hh +++ b/src/GlueXHitPSpoint.hh @@ -20,6 +20,7 @@ class GlueXHitPSpoint : public G4VHit { public: GlueXHitPSpoint() {} + GlueXHitPSpoint(const GlueXHitPSpoint &src); int operator==(const GlueXHitPSpoint &right) const; GlueXHitPSpoint &operator+=(const GlueXHitPSpoint &right); diff --git a/src/GlueXHitPStile.cc b/src/GlueXHitPStile.cc index ba3620c..b44ed2f 100644 --- a/src/GlueXHitPStile.cc +++ b/src/GlueXHitPStile.cc @@ -14,6 +14,13 @@ GlueXHitPStile::GlueXHitPStile(G4int arm, G4int column) column_(column) {} +GlueXHitPStile::GlueXHitPStile(const GlueXHitPStile &src) +{ + arm_ = src.arm_; + column_ = src.column_; + hits = src.hits; +} + int GlueXHitPStile::operator==(const GlueXHitPStile &right) const { if (arm_ != right.arm_ || column_ != right.column_) diff --git a/src/GlueXHitPStile.hh b/src/GlueXHitPStile.hh index 38ee4c9..a161d7c 100644 --- a/src/GlueXHitPStile.hh +++ b/src/GlueXHitPStile.hh @@ -19,7 +19,9 @@ class GlueXHitPStile : public G4VHit { public: + GlueXHitPStile() {} GlueXHitPStile(G4int arm, G4int column); + GlueXHitPStile(const GlueXHitPStile &src); int operator==(const GlueXHitPStile &right) const; GlueXHitPStile &operator+=(const GlueXHitPStile &right); diff --git a/src/GlueXHitSTCpaddle.cc b/src/GlueXHitSTCpaddle.cc index 886b28d..3669cd5 100644 --- a/src/GlueXHitSTCpaddle.cc +++ b/src/GlueXHitSTCpaddle.cc @@ -13,6 +13,12 @@ GlueXHitSTCpaddle::GlueXHitSTCpaddle(G4int sector) sector_(sector) {} +GlueXHitSTCpaddle::GlueXHitSTCpaddle(const GlueXHitSTCpaddle &src) +{ + sector_ = src.sector_; + hits = src.hits; +} + int GlueXHitSTCpaddle::operator==(const GlueXHitSTCpaddle &right) const { if (sector_ != right.sector_) diff --git a/src/GlueXHitSTCpaddle.hh b/src/GlueXHitSTCpaddle.hh index 3183e7e..53a8b96 100644 --- a/src/GlueXHitSTCpaddle.hh +++ b/src/GlueXHitSTCpaddle.hh @@ -19,7 +19,9 @@ class GlueXHitSTCpaddle : public G4VHit { public: + GlueXHitSTCpaddle() {} GlueXHitSTCpaddle(G4int sector); + GlueXHitSTCpaddle(const GlueXHitSTCpaddle &src); int operator==(const GlueXHitSTCpaddle &right) const; GlueXHitSTCpaddle &operator+=(const GlueXHitSTCpaddle &right); diff --git a/src/GlueXHitSTCpoint.cc b/src/GlueXHitSTCpoint.cc index 1f32a33..ff6d156 100644 --- a/src/GlueXHitSTCpoint.cc +++ b/src/GlueXHitSTCpoint.cc @@ -8,6 +8,24 @@ G4ThreadLocal G4Allocator* GlueXHitSTCpointAllocator = 0; +GlueXHitSTCpoint::GlueXHitSTCpoint(const GlueXHitSTCpoint &src) +{ + E_GeV = src.E_GeV; + dEdx_GeV_cm = src.dEdx_GeV_cm; + phi_rad = src.phi_rad; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + r_cm = src.r_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + sector_ = src.sector_; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitSTCpoint::operator==(const GlueXHitSTCpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitSTCpoint.hh b/src/GlueXHitSTCpoint.hh index 43cc107..49420d3 100644 --- a/src/GlueXHitSTCpoint.hh +++ b/src/GlueXHitSTCpoint.hh @@ -20,6 +20,7 @@ class GlueXHitSTCpoint : public G4VHit { public: GlueXHitSTCpoint() {} + GlueXHitSTCpoint(const GlueXHitSTCpoint &src); int operator==(const GlueXHitSTCpoint &right) const; GlueXHitSTCpoint &operator+=(const GlueXHitSTCpoint &right); diff --git a/src/GlueXHitTPOLpoint.cc b/src/GlueXHitTPOLpoint.cc index 79719da..eb5e00f 100644 --- a/src/GlueXHitTPOLpoint.cc +++ b/src/GlueXHitTPOLpoint.cc @@ -8,6 +8,22 @@ G4ThreadLocal G4Allocator* GlueXHitTPOLpointAllocator = 0; +GlueXHitTPOLpoint::GlueXHitTPOLpoint(const GlueXHitTPOLpoint &src) +{ + E_GeV = src.E_GeV; + dEdx_GeV_cm = src.dEdx_GeV_cm; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + phi_rad = src.phi_rad; + r_cm = src.r_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitTPOLpoint::operator==(const GlueXHitTPOLpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitTPOLpoint.hh b/src/GlueXHitTPOLpoint.hh index 4e4b330..f288123 100644 --- a/src/GlueXHitTPOLpoint.hh +++ b/src/GlueXHitTPOLpoint.hh @@ -20,6 +20,7 @@ class GlueXHitTPOLpoint : public G4VHit { public: GlueXHitTPOLpoint() {} + GlueXHitTPOLpoint(const GlueXHitTPOLpoint &src); int operator==(const GlueXHitTPOLpoint &right) const; GlueXHitTPOLpoint &operator+=(const GlueXHitTPOLpoint &right); diff --git a/src/GlueXHitTPOLwedge.cc b/src/GlueXHitTPOLwedge.cc index 7ba353c..42cc0b1 100644 --- a/src/GlueXHitTPOLwedge.cc +++ b/src/GlueXHitTPOLwedge.cc @@ -13,6 +13,14 @@ GlueXHitTPOLwedge::GlueXHitTPOLwedge(G4int sector, G4int ring) ring_(ring), sector_(sector) {} + +GlueXHitTPOLwedge::GlueXHitTPOLwedge(const GlueXHitTPOLwedge &src) +{ + ring_ = src.ring_; + sector_ = src.sector_; + hits = src.hits; +} + int GlueXHitTPOLwedge::operator==(const GlueXHitTPOLwedge &right) const { if (sector_ != right.sector_ || ring_ != right.ring_) diff --git a/src/GlueXHitTPOLwedge.hh b/src/GlueXHitTPOLwedge.hh index 0f80f72..23b4297 100644 --- a/src/GlueXHitTPOLwedge.hh +++ b/src/GlueXHitTPOLwedge.hh @@ -19,7 +19,9 @@ class GlueXHitTPOLwedge : public G4VHit { public: + GlueXHitTPOLwedge() {} GlueXHitTPOLwedge(G4int sector, G4int ring=0); + GlueXHitTPOLwedge(const GlueXHitTPOLwedge &src); int operator==(const GlueXHitTPOLwedge &right) const; GlueXHitTPOLwedge &operator+=(const GlueXHitTPOLwedge &right); diff --git a/src/GlueXHitUPVbar.cc b/src/GlueXHitUPVbar.cc index 6073614..9ae2a53 100644 --- a/src/GlueXHitUPVbar.cc +++ b/src/GlueXHitUPVbar.cc @@ -14,6 +14,13 @@ GlueXHitUPVbar::GlueXHitUPVbar(G4int layer, G4int row) row_(row) {} +GlueXHitUPVbar::GlueXHitUPVbar(const GlueXHitUPVbar &src) +{ + layer_ = src.layer_; + row_ = src.row_; + hits = src.hits; +} + int GlueXHitUPVbar::operator==(const GlueXHitUPVbar &right) const { if (layer_ != right.layer_ || row_ != right.row_ ) diff --git a/src/GlueXHitUPVbar.hh b/src/GlueXHitUPVbar.hh index 3b5ee3e..658d258 100644 --- a/src/GlueXHitUPVbar.hh +++ b/src/GlueXHitUPVbar.hh @@ -19,7 +19,9 @@ class GlueXHitUPVbar : public G4VHit { public: + GlueXHitUPVbar() {} GlueXHitUPVbar(G4int layer, G4int row); + GlueXHitUPVbar(const GlueXHitUPVbar &src); int operator==(const GlueXHitUPVbar &right) const; GlueXHitUPVbar &operator+=(const GlueXHitUPVbar &right); diff --git a/src/GlueXHitUPVpoint.cc b/src/GlueXHitUPVpoint.cc index 8157ab7..c061b1a 100644 --- a/src/GlueXHitUPVpoint.cc +++ b/src/GlueXHitUPVpoint.cc @@ -8,6 +8,22 @@ G4ThreadLocal G4Allocator* GlueXHitUPVpointAllocator = 0; +GlueXHitUPVpoint::GlueXHitUPVpoint(const GlueXHitUPVpoint &src) +{ + E_GeV = src.E_GeV; + primary_ = src.primary_; + ptype_G3 = src.ptype_G3; + px_GeV = src.px_GeV; + py_GeV = src.py_GeV; + pz_GeV = src.pz_GeV; + x_cm = src.x_cm; + y_cm = src.y_cm; + z_cm = src.z_cm; + t_ns = src.t_ns; + track_ = src.track_; + trackID_ = src.trackID_; +} + int GlueXHitUPVpoint::operator==(const GlueXHitUPVpoint &right) const { if (E_GeV != right.E_GeV || diff --git a/src/GlueXHitUPVpoint.hh b/src/GlueXHitUPVpoint.hh index 74cc6f2..3f4c371 100644 --- a/src/GlueXHitUPVpoint.hh +++ b/src/GlueXHitUPVpoint.hh @@ -20,6 +20,7 @@ class GlueXHitUPVpoint : public G4VHit { public: GlueXHitUPVpoint() {} + GlueXHitUPVpoint(const GlueXHitUPVpoint &src); int operator==(const GlueXHitUPVpoint &right) const; GlueXHitUPVpoint &operator+=(const GlueXHitUPVpoint &right); diff --git a/src/GlueXPhotonBeamGenerator.cc b/src/GlueXPhotonBeamGenerator.cc index 6cee7ab..d0805e9 100644 --- a/src/GlueXPhotonBeamGenerator.cc +++ b/src/GlueXPhotonBeamGenerator.cc @@ -33,12 +33,17 @@ double GlueXPhotonBeamGenerator::fBeamBucketPeriod = 4. * ns; double GlueXPhotonBeamGenerator::fBeamStartZ = -24 * m; double GlueXPhotonBeamGenerator::fBeamDiameter = 0.5 * cm; double GlueXPhotonBeamGenerator::fBeamVelocity = 2.99792e8 * m/s; +double GlueXPhotonBeamGenerator::fBeamOffset[2] = {0,0}; ImportanceSampler GlueXPhotonBeamGenerator::fCoherentPDFx; ImportanceSampler GlueXPhotonBeamGenerator::fIncoherentPDFlogx; ImportanceSampler GlueXPhotonBeamGenerator::fIncoherentPDFy; double GlueXPhotonBeamGenerator::fIncoherentPDFtheta02; +int GlueXPhotonBeamGenerator::fForceFixedPolarization = false; +double GlueXPhotonBeamGenerator::fFixedPolarization = 0; +double GlueXPhotonBeamGenerator::fFixedPolarization_phi = 0; + GlueXPseudoDetectorTAG *GlueXPhotonBeamGenerator::fTagger = 0; GlueXPhotonBeamGenerator::GlueXPhotonBeamGenerator(CobremsGeneration *gen) @@ -92,14 +97,33 @@ GlueXPhotonBeamGenerator::GlueXPhotonBeamGenerator(CobremsGeneration *gen) // warnings about Pcut violations. double raddz = fCobrems->getTargetThickness() * m; - fCoherentPDFx.Pcut = .003 * (raddz / 20e-6); - fIncoherentPDFlogx.Pcut = .003 * (raddz / 20e-6); + fCoherentPDFx.Pcut = .003 * (raddz / (20e-6 * m)); + fIncoherentPDFlogx.Pcut = .003 * (raddz / (20e-6 * m)); prepareImportanceSamplingPDFs(); + + // Create interface for interactive commands + + fMessenger = new G4GenericMessenger(this, "/PhotonBeam/", + "Photon beam generator control"); + fMessenger->DeclareMethod("enableFixedPolarization", + &GlueXPhotonBeamGenerator::enableFixedPolarization, + "Tell the photon beam generator to force a fixed polarization\n" + " on all beam photons created by the simulation.\n" + " Arguments are:\n" + " polarization: value in the range [0,1]\n" + " phi: azimuthal angle (degrees) [0, 180]"); + fMessenger->DeclareMethod("disableFixedPolarization", + &GlueXPhotonBeamGenerator::disableFixedPolarization, + "Tell the photon beam generator not to force a fixed polarization\n" + " on beam photons created by the simulation."); + std::cout << "GlueXPhotonBeamGenerator initialization complete." << std::endl; } GlueXPhotonBeamGenerator::~GlueXPhotonBeamGenerator() -{} +{ + delete fMessenger; +} void GlueXPhotonBeamGenerator::prepareImportanceSamplingPDFs() { @@ -158,6 +182,7 @@ void GlueXPhotonBeamGenerator::prepareImportanceSamplingPDFs() fIncoherentPDFlogx.density[i] /= sum * dlogx; fIncoherentPDFlogx.integral[i] /= sum; } + fIncoherentPDFlogx.Pcut = 2 * sum * dlogx; // Compute approximate PDF for dNi/dy fIncoherentPDFtheta02 = 1.8; @@ -292,19 +317,20 @@ void GlueXPhotonBeamGenerator::GenerateBeamPhoton(G4Event* anEvent, double t0) double thetax = thxBeam + thxMS - targetThetax - thxMosaic; double thetay = thyBeam + thyMS - targetThetay - thyMosaic; double thetaz = -targetThetaz; - fCobrems->setTargetOrientation(thetax, thetay, thetaz); + fCobrems->setTargetOrientation(thetax/radian, thetay/radian, thetaz/radian); // Generate with importance sampling double x = 0; double phi = 0; double theta2 = 0; double polarization = 0; + double polarization_phi = 0; double Scoherent = fCoherentPDFx.Npassed * (fCoherentPDFx.Ntested / (fCoherentPDFx.Psum + 1e-99)); double Sincoherent = fIncoherentPDFlogx.Npassed * (fIncoherentPDFlogx.Ntested / (fIncoherentPDFlogx.Psum + 1e-99)); - if (Scoherent < Sincoherent) { + if (targetThetax != 0 && Scoherent < Sincoherent) { while (true) { // try coherent generation ++fCoherentPDFx.Ntested; @@ -350,7 +376,8 @@ void GlueXPhotonBeamGenerator::GenerateBeamPhoton(G4Event* anEvent, double t0) double uq = freq * G4UniformRand(); int j = ImportanceSampler::search(uq, fCobrems->fQ2weight); theta2 = fCobrems->fQ2theta2[j]; - polarization = fCobrems->Polarization(x, theta2); + polarization = fCobrems->Polarization(x, theta2, phi); + polarization_phi = M_PI / 2; break; } } @@ -404,7 +431,8 @@ void GlueXPhotonBeamGenerator::GenerateBeamPhoton(G4Event* anEvent, double t0) ++fIncoherentPDFlogx.Npassed; phi = 2*M_PI * G4UniformRand(); - polarization = 0; + polarization = fCobrems->AbremsPolarization(x, theta2, phi); + polarization_phi = phi - M_PI / 2; break; } } @@ -430,9 +458,9 @@ void GlueXPhotonBeamGenerator::GenerateBeamPhoton(G4Event* anEvent, double t0) #endif // Put the radiator back the way you found it - fCobrems->setTargetOrientation(targetThetax, - targetThetay, - targetThetaz); + fCobrems->setTargetOrientation(targetThetax/radian, + targetThetay/radian, + targetThetaz/radian); // Define the particle kinematics and polarization in lab coordinates G4ParticleDefinition *part = GlueXPrimaryGeneratorAction::GetParticle("gamma"); @@ -458,8 +486,20 @@ void GlueXPhotonBeamGenerator::GenerateBeamPhoton(G4Event* anEvent, double t0) colx += BEAM_BOX_SIZE * (G4UniformRand() - 0.5); coly += BEAM_BOX_SIZE * (G4UniformRand() - 0.5); #endif + colx += fBeamOffset[0]; + coly += fBeamOffset[1]; G4ThreeVector vtx(colx, coly, fBeamStartZ); - G4ThreeVector pol(0, polarization, -polarization * py / pz); + if (fForceFixedPolarization) { + polarization = fFixedPolarization; + polarization_phi = fFixedPolarization_phi; + } + G4ThreeVector pol(polarization * cos(polarization_phi), + polarization * sin(polarization_phi), + -(px * polarization * cos(polarization_phi) + + py * polarization * sin(polarization_phi)) / pz); + // use upper half-space to define the polarization plane + if (pol[2] < 0) + pol = -pol; G4ThreeVector mom(px, py, pz); // If beam photon is primary particle, use it to initialize event info @@ -498,9 +538,25 @@ void GlueXPhotonBeamGenerator::GenerateBeamPhoton(G4Event* anEvent, double t0) anEvent->AddPrimaryVertex(vertex); } + // Include information about the radiating electron, but do not track it + G4ParticleDefinition *ve = GlueXPrimaryGeneratorAction::GetParticle("electron"); + double vpx = Ebeam * thxBeam; + double vpy = Ebeam * thyBeam; + double vpz = sqrt(Ebeam*Ebeam - vpx*vpx - vpy*vpy); + G4PrimaryParticle *velectron = new G4PrimaryParticle(ve, vpx, vpy, vpz); + double colvx = radx + colDist * thxBeam; + double colvy = rady + colDist * thyBeam; + colvx += fBeamOffset[0]; + colvy += fBeamOffset[1]; + G4ThreeVector vvtx(colvx, colvy, fBeamStartZ); + G4PrimaryVertex *vvertex = new G4PrimaryVertex(vvtx, tvtx); + vvertex->SetPrimary(velectron); + event_info->AddPrimaryVertex(*vvertex); + delete vvertex; + // If running in event generation only mode, default is not to // save the event to the output file. This will be set back to - // true if // the beam particle makes it to the reference plane. + // true if the beam particle makes it to the reference plane. if (fGenerateNotSimulate == -1) { event_info->SetKeepEvent(0); } @@ -531,16 +587,18 @@ double GlueXPhotonBeamGenerator::GenerateTriggerTime(const G4Event *event) { // The primary interaction vertex time is referenced to a clock // whose t=0 is synchronized to the crossing of a beam bunch - // through the target midplane. This beam bunch may not contain - // the beam particle whose interaction generated the vertex, - // but it represents best-guess based on the arrival time of - // the L1 trigger signal. The spread in the L1 relative to the + // through the clock reference plane. This beam bunch may not + // contain the beam particle whose interaction generated the + // vertex, but it represents best-guess based on the arrival time + // of the L1 trigger signal. The spread in the L1 relative to the // interacting bunch time is parameterized as a Gaussian. extern int run_number; static int last_run_number = 0; if (run_number != last_run_number) { fBeamBucketPeriod = getBeamBucketPeriod(run_number); + double refZ = getRFreferencePlaneZ(run_number); + GlueXPrimaryGeneratorAction::setRFreferencePlaneZ(refZ); last_run_number = run_number; } double L1sigmat = GlueXPrimaryGeneratorAction::getL1triggerTimeSigma(); @@ -605,3 +663,36 @@ double GlueXPhotonBeamGenerator::getBeamBucketPeriod(int runno) } return fBeamBucketPeriod; } + +double GlueXPhotonBeamGenerator::getRFreferencePlaneZ(int runno) +{ + // Look up the reference plane Z for this run in ccdb + // unless the user has already set the value by hand. + + double refZ = 65 * cm; + + if (runno > 0) { + jana::JCalibration *jcalib = japp->GetJCalibration(runno); + G4cout << "JCalibration context: " << jcalib->GetContext() + << G4endl; + std::map result; + std::string map_key("/PHOTON_BEAM/RF/reference_plane_z"); + if (jcalib->Get(map_key, result)) { + G4cerr << "Error in GlueXPhotonBeamGenerator::getRFreferencePlaneZ" + << " - error fetching " << map_key << " from ccdb, " + << "keeping default value " << refZ / cm << " cm." << G4endl; + } + else if (result.find("z_position") != result.end()) { + refZ = result["z_position"] * cm; + G4cout << "Info: RF reference plane set to " << refZ / cm << " cm." + << G4endl; + } + else { + G4cerr << "Error in GlueXPhotonBeamGenerator::getRFreferencePlaneZ" + << " - error finding value for " << map_key + << " in ccdb, cannot continue." << G4endl; + exit(-1); + } + } + return refZ; +} diff --git a/src/GlueXPhotonBeamGenerator.hh b/src/GlueXPhotonBeamGenerator.hh index 5d9d777..ca56de1 100644 --- a/src/GlueXPhotonBeamGenerator.hh +++ b/src/GlueXPhotonBeamGenerator.hh @@ -13,6 +13,7 @@ #define GlueXPhotonBeamGenerator_H #include +#include #include #include #include @@ -42,6 +43,7 @@ class GlueXPhotonBeamGenerator: public G4VPrimaryGenerator static double fBeamStartZ; static double fBeamDiameter; static double fBeamVelocity; + static double fBeamOffset[2]; static ImportanceSampler fCoherentPDFx; static ImportanceSampler fIncoherentPDFlogx; @@ -50,6 +52,12 @@ class GlueXPhotonBeamGenerator: public G4VPrimaryGenerator void prepareImportanceSamplingPDFs(); + static int fForceFixedPolarization; + static double fFixedPolarization; + static double fFixedPolarization_phi; + + G4GenericMessenger *fMessenger; + public: static void setBeamDiameter(double D) { fBeamDiameter = D; @@ -60,6 +68,14 @@ class GlueXPhotonBeamGenerator: public G4VPrimaryGenerator static double getBeamVelocity() { return fBeamVelocity; } + static void setBeamOffset(double x, double y) { + fBeamOffset[0] = x; + fBeamOffset[1] = y; + } + static double getBeamOffset(int i) { + return fBeamOffset[i]; + } + static double getRFreferencePlaneZ(int runno=0); static double getBeamBucketPeriod(int runno=0); static void setBeamBucketPeriod(double period) { fBeamBucketPeriod = period; @@ -70,6 +86,14 @@ class GlueXPhotonBeamGenerator: public G4VPrimaryGenerator static double getBeamStartZ() { return fBeamStartZ; } + void enableFixedPolarization(double polar, double phi_deg) { + fFixedPolarization = polar; + fFixedPolarization_phi = phi_deg * M_PI/180; + fForceFixedPolarization = true; + } + void disableFixedPolarization() { + fForceFixedPolarization = false; + } private: GlueXPhotonBeamGenerator(const GlueXPhotonBeamGenerator &src) {} diff --git a/src/GlueXPhysicsList.cc b/src/GlueXPhysicsList.cc index 68123bd..7b31909 100644 --- a/src/GlueXPhysicsList.cc +++ b/src/GlueXPhysicsList.cc @@ -134,6 +134,19 @@ GlueXPhysicsList::GlueXPhysicsList(const GlueXDetectorConstruction *geometry, GlueXPhysicsList::~GlueXPhysicsList() {} +void GlueXPhysicsList::ConstructParticle() +{ + G4VModularPhysicsList::ConstructParticle(); +#if VERBOSE_PARTICLES + GetParticleIterator()->reset(); + while ( (*GetParticleIterator())() ) { + G4ParticleDefinition* particle = GetParticleIterator()->value(); + G4String particleName = particle->GetParticleName(); + G4cout << "*** particle type " << particleName << G4endl; + } +#endif +} + void GlueXPhysicsList::ConstructProcess() { // Read special cuts from the user options file @@ -180,7 +193,7 @@ void GlueXPhysicsList::ConstructProcess() #if USING_DIRACXX // Add a process for TPOL beam photon pair conversion process - fBeamConversion = new GlueXBeamConversionProcess("TPOL beam conversion"); + fBeamConversion = new GlueXBeamConversionProcess("TPolBeamConversion"); #endif // create the special cuts processes and register them @@ -253,7 +266,7 @@ void GlueXPhysicsList::ConstructProcess() else continue; } - else if (particleName == "muon-" || particleName == "muon+") { + else if (particleName == "mu-" || particleName == "mu+") { if (KEcut_muon > 0) { G4UserLimits *mlimits = new G4UserLimits(); mlimits->SetUserMaxTime(tcut); @@ -266,6 +279,9 @@ void GlueXPhysicsList::ConstructProcess() else continue; } + else if (particleName == "GenericIon") { + // mgr->DumpInfo(); + } else { continue; } @@ -584,7 +600,7 @@ void GlueXPhysicsList::SelectActiveProcesses(G4int verbosity) } } if (fOptions->Find("CKOV", flags)) { - if (flags.find(1) != flags.end() || flags[1] != 0) { + if (flags.find(1) == flags.end() || flags[1] != 0) { DoCerenkovRadiation(1); if (verbosity > 0) { G4cout << "*** Cerenkov radiation enabled for charged particles." @@ -593,7 +609,7 @@ void GlueXPhysicsList::SelectActiveProcesses(G4int verbosity) } } if (fOptions->Find("LABS", flags)) { - if (flags.find(1) != flags.end() || flags[1] != 0) { + if (flags.find(1) == flags.end() || flags[1] != 0) { DoOpticalAbsorption(1); if (verbosity > 0) { G4cout << "*** Light absorption enabled for optical photons." @@ -622,12 +638,12 @@ void GlueXPhysicsList::DoProcessReordering() G4VProcess *paraWorld=0; for (int j=0; j < procs->size(); ++j) { std::string procname((*procs)[j]->GetProcessName()); - if (procname.substr(0, 15) == "Parallel World ") { + if (procname.substr(0, 13) == "ParallelWorld") { paraWorld = (*procs)[j]; } } if (paraWorld == 0) { - G4cerr << "Parallel World process not found, cannot continue!" + G4cerr << "ParallelWorld process not found, cannot continue!" << G4endl; exit(1); } diff --git a/src/GlueXPhysicsList.hh b/src/GlueXPhysicsList.hh index c259d79..1f6b8df 100644 --- a/src/GlueXPhysicsList.hh +++ b/src/GlueXPhysicsList.hh @@ -31,6 +31,7 @@ class GlueXPhysicsList: public G4VModularPhysicsList G4int verbosity=0); virtual ~GlueXPhysicsList(); + virtual void ConstructParticle(); virtual void ConstructProcess(); virtual void SetCuts(); @@ -59,7 +60,7 @@ class GlueXPhysicsList: public G4VModularPhysicsList #endif G4OpticalPhysics *fOpticalPhysics; -#ifndef G4VUSERPHYSICSLIST_HAS_GETPARTICLEITERATOR +#ifndef G4VERSION_10_04_OR_LATER // This member function gets introduced into base class // G4VUserPhysicsList in release Geant4.10.03, but until // we abandon ability to build under previous releases, diff --git a/src/GlueXPrimaryGenerator.cc b/src/GlueXPrimaryGenerator.cc index 572582a..b6d7bfa 100644 --- a/src/GlueXPrimaryGenerator.cc +++ b/src/GlueXPrimaryGenerator.cc @@ -14,6 +14,8 @@ #include "GlueXPrimaryGeneratorAction.hh" #include "GlueXUserEventInformation.hh" #include "G4SystemOfUnits.hh" +#include "G4UnitsTable.hh" +#include "G4RunManager.hh" #include @@ -27,13 +29,13 @@ GlueXPrimaryGenerator::~GlueXPrimaryGenerator() void GlueXPrimaryGenerator::GeneratePrimaryVertex(G4Event *event) { hddm_s::HDDM *hddmevent = new hddm_s::HDDM; - try { - *fHDDMistream >> *hddmevent; - } - catch(std::exception e) { - G4cout << e.what() << G4endl; - event->SetEventAborted(); - return; + while (hddmevent->getPhysicsEvents().size() == 0) { + if (! (*fHDDMistream >> *hddmevent)) { + event->SetEventAborted(); + G4cout << "End of file on hddm input, ending the run here." << std::endl; + G4RunManager::GetRunManager()->AbortRun(); + return; + } } // Store generated event info so it can be written to output file @@ -50,28 +52,44 @@ void GlueXPrimaryGenerator::GeneratePrimaryVertex(G4Event *event) return; } hddm_s::VertexList::iterator it_vertex; + it_vertex = vertices.begin(); + event->SetEventID(it_vertex->getEventNo()); + G4ThreeVector vtx(GetParticlePosition()); + double tvtx(GetParticleTime()); + hddm_s::Origin &origin = it_vertex->getOrigin(); + double x = origin.getVx() * cm; + double y = origin.getVy() * cm; + double z = origin.getVz() * cm; + double t = origin.getT() * ns; + if (x == 0 && y == 0 && z == 0) { + tvtx = (t == 0)? tvtx : 0; + } + else { + double beamVelocity = GlueXPhotonBeamGenerator::getBeamVelocity(); + if (t == 0) + tvtx += (z - vtx[2]) / beamVelocity; + else + tvtx = 0; + vtx[0] = 0; + vtx[1] = 0; + vtx[2] = 0; + } for (it_vertex = vertices.begin(); it_vertex != vertices.end(); ++it_vertex) { - event->SetEventID(it_vertex->getEventNo()); hddm_s::Origin &origin = it_vertex->getOrigin(); double x = origin.getVx() * cm; double y = origin.getVy() * cm; double z = origin.getVz() * cm; double t = origin.getT() * ns; - if (x == 0 && y == 0 && z == 0) { - G4ThreeVector vtx(GetParticlePosition()); - x = vtx[0]; - y = vtx[1]; - z = vtx[2]; - origin.setVx(x/cm); - origin.setVy(y/cm); - origin.setVz(z/cm); - } - if (t == 0) { - t = GetParticleTime(); - origin.setT(t/ns); - } + x += vtx[0]; + y += vtx[1]; + z += vtx[2]; + t += tvtx; + origin.setVx(x/cm); + origin.setVy(y/cm); + origin.setVz(z/cm); + origin.setT(t/ns); G4ThreeVector pos(x, y, z); G4PrimaryVertex* vertex = new G4PrimaryVertex(pos, t); hddm_s::ProductList &products = it_vertex->getProducts(); @@ -87,7 +105,7 @@ void GlueXPrimaryGenerator::GeneratePrimaryVertex(G4Event *event) int g3type = it_product->getType(); int pdgtype = it_product->getPdgtype(); G4ParticleDefinition *part; - if (pdgtype > 0 && pdgtype < 999999) { + if (pdgtype > 0) { part = GlueXPrimaryGeneratorAction::GetParticle(pdgtype); } else if (g3type > 0) { @@ -98,7 +116,10 @@ void GlueXPrimaryGenerator::GeneratePrimaryVertex(G4Event *event) #endif } else { - G4cerr << "Unknown particle found in input MC record, " + G4cerr << "=== WARNING in GlueXPrimaryGenerator::" + "GeneratePrimaryVertex ===" + << G4endl + << " Unknown particle found in input MC record, " << "geant3 type " << g3type << ", PDG type " << pdgtype << ", failing over to geantino!" @@ -108,10 +129,30 @@ void GlueXPrimaryGenerator::GeneratePrimaryVertex(G4Event *event) hddm_s::Momentum &momentum = it_product->getMomentum(); double px = momentum.getPx() * GeV; double py = momentum.getPy() * GeV; - double pz = momentum.getPz() * GeV; - double Etot = momentum.getE() * GeV; - vertex->SetPrimary(new G4PrimaryParticle(part, px, py, pz, Etot)); + double pz = momentum.getPz() * GeV; + double mass1 = part->GetPDGMass(); + double p = sqrt(px*px + py*py + pz*pz); + double Etot = sqrt(mass1*mass1 + p*p); + G4PrimaryParticle *pp = new G4PrimaryParticle(part, px, py, pz, Etot); + vertex->SetPrimary(pp); event_info->SetGlueXTrackID(++Nprimaries, trackId); + double mass2 = sqrt(Etot*Etot - p*p); + if (fabs(mass1 - mass2) > mass2 * 1e-3) { + G4cerr << "=== WARNING in GlueXPrimaryGenerator::" + "GeneratePrimaryVertex ===" + << G4endl + << " " << part->GetParticleName() + << " found in input MC record, " + << "geant3 type " << g3type + << ", PDG type " << pdgtype + << " has unphysical mass: " + << G4endl + << " expected " << G4BestUnit(mass1, "Energy") + << ", found " << G4BestUnit(mass2, "Energy") + << ", difference " + << G4BestUnit(mass2 - mass1, "Energy") + << G4endl; + } } event->AddPrimaryVertex(vertex); } diff --git a/src/GlueXPrimaryGenerator.hh b/src/GlueXPrimaryGenerator.hh index 4cd5c04..c03196d 100644 --- a/src/GlueXPrimaryGenerator.hh +++ b/src/GlueXPrimaryGenerator.hh @@ -24,8 +24,6 @@ class GlueXPrimaryGenerator: public G4VPrimaryGenerator virtual void GeneratePrimaryVertex(G4Event *event); - double GetBeamEnergy(G4Event *event); - protected: hddm_s::istream *fHDDMistream; diff --git a/src/GlueXPrimaryGeneratorAction.cc b/src/GlueXPrimaryGeneratorAction.cc index 02c403a..d00af9c 100644 --- a/src/GlueXPrimaryGeneratorAction.cc +++ b/src/GlueXPrimaryGeneratorAction.cc @@ -8,9 +8,12 @@ #include "GlueXPrimaryGenerator.hh" #include "GlueXUserEventInformation.hh" #include "GlueXUserOptions.hh" +#include "G4OpticalPhoton.hh" #include "G4Event.hh" #include "G4ParticleTable.hh" +#include "G4ProcessManager.hh" +#include "G4IonTable.hh" #include "G4SystemOfUnits.hh" #include "Randomize.hh" @@ -35,6 +38,7 @@ double GlueXPrimaryGeneratorAction::fBeamBackgroundRate = 0; double GlueXPrimaryGeneratorAction::fBeamBackgroundGateStart = 0; double GlueXPrimaryGeneratorAction::fBeamBackgroundGateStop = 0; double GlueXPrimaryGeneratorAction::fL1triggerTimeSigma = 10 * ns; +double GlueXPrimaryGeneratorAction::fRFreferencePlaneZ = 65 * cm; double GlueXPrimaryGeneratorAction::fTargetCenterZ = 65 * cm; double GlueXPrimaryGeneratorAction::fTargetLength = 29.9746 * cm; @@ -71,6 +75,146 @@ GlueXPrimaryGeneratorAction::GlueXPrimaryGeneratorAction() exit(-1); } + // get positions for LUT from XML geometry + std::map dirclutpars; + std::map dircledpars; + if (instanceCount == 1) { + + if (user_opts->Find("DIRCLUT", dirclutpars)) { + + extern int run_number; + extern jana::JApplication *japp; + if (japp == 0) { + G4cerr << "Error in GlueXPrimaryGeneratorAction constructor - " + << "jana global DApplication object not set, " + << "cannot continue." << G4endl; + exit(-1); + } + jana::JGeometry *jgeom = japp->GetJGeometry(run_number); + if (japp == 0) { // dummy + jgeom = 0; + G4cout << "DIRC: ALL parameters loaded from ccdb" << G4endl; + } + + vectorDIRC; + vectorDRCC; + vectorDCML00_XYZ; + vectorDCML01_XYZ; + vectorDCML10_XYZ; + vectorDCML11_XYZ; + vectorWNGL00_XYZ; + vectorWNGL01_XYZ; + vectorWNGL10_XYZ; + vectorWNGL11_XYZ; + vectorOWDG_XYZ; + jgeom->Get("//section/composition/posXYZ[@volume='DIRC']/@X_Y_Z", DIRC); + jgeom->Get("//composition[@name='DIRC']/posXYZ[@volume='DRCC']/@X_Y_Z", DRCC); + jgeom->Get("//composition[@name='DRCC']/posXYZ[@volume='DCML00']/@X_Y_Z", DCML00_XYZ); + jgeom->Get("//composition[@name='DRCC']/posXYZ[@volume='DCML01']/@X_Y_Z", DCML01_XYZ); + jgeom->Get("//composition[@name='DRCC']/posXYZ[@volume='DCML10']/@X_Y_Z", DCML10_XYZ); + jgeom->Get("//composition[@name='DRCC']/posXYZ[@volume='DCML11']/@X_Y_Z", DCML11_XYZ); + jgeom->Get("//composition[@name='DCML00']/posXYZ[@volume='WNGL']/@X_Y_Z", WNGL00_XYZ); + jgeom->Get("//composition[@name='DCML01']/posXYZ[@volume='WNGL']/@X_Y_Z", WNGL01_XYZ); + jgeom->Get("//composition[@name='DCML10']/posXYZ[@volume='WNGL']/@X_Y_Z", WNGL10_XYZ); + jgeom->Get("//composition[@name='DCML11']/posXYZ[@volume='WNGL']/@X_Y_Z", WNGL11_XYZ); + jgeom->Get("//composition[@name='DCML11']/posXYZ[@volume='WNGL']/@X_Y_Z", WNGL11_XYZ); + jgeom->Get("//trd[@name='OWDG']/@Xmp_Ymp_Z", OWDG_XYZ); + DIRC_LUT_Z = (DIRC[2] + DRCC[2] + DCML01_XYZ[2] + 0.8625) * cm; + DIRC_QZBL_DY = 3.5 * cm; // nominal width to generate LUT + DIRC_QZBL_DZ = 1.725 * cm; // nominal thickness to generate LUT + DIRC_OWDG_DZ = OWDG_XYZ[4]; + + // set array of bar positions + for (int i=0; i<48; i++) { + vectorDCBR_XYZ; + if (i<12) { + std::stringstream geomDCML10; + geomDCML10 << "//composition[@name='DCML10']/posXYZ[@volume='DCBR" + << std::setfill('0') << std::setw(2) << i << "']/@X_Y_Z"; + jgeom->Get(geomDCML10.str(), DCBR_XYZ); + DIRC_BAR_Y[i] = (DCML10_XYZ[1] - DCBR_XYZ[1]) * cm; + DIRC_LUT_X[i] = (DIRC[0] + DRCC[0] + DCML10_XYZ[0] - WNGL10_XYZ[0] + DIRC_OWDG_DZ) * cm; + } + else if (i<24) { + std::stringstream geomDCML11; + geomDCML11 << "//composition[@name='DCML11']/posXYZ[@volume='DCBR" + << std::setfill('0') << std::setw(2) << i << "']/@X_Y_Z"; + jgeom->Get(geomDCML11.str(), DCBR_XYZ); + DIRC_BAR_Y[i] = (DCML11_XYZ[1] - DCBR_XYZ[1]) * cm; + DIRC_LUT_X[i] = (DIRC[0] + DRCC[0] + DCML11_XYZ[0] - WNGL11_XYZ[0] + DIRC_OWDG_DZ) * cm; + } + else if (i<36) { + std::stringstream geomDCML01; + geomDCML01 << "//composition[@name='DCML01']/posXYZ[@volume='DCBR" + << std::setfill('0') << std::setw(2) << i << "']/@X_Y_Z"; + jgeom->Get(geomDCML01.str(), DCBR_XYZ); + DIRC_BAR_Y[i] = (DCML01_XYZ[1] + DCBR_XYZ[1]) * cm; + DIRC_LUT_X[i] = (DIRC[0] + DRCC[0] + DCML01_XYZ[0] + WNGL01_XYZ[0] - DIRC_OWDG_DZ) * cm; + } + else if (i<48) { + std::stringstream geomDCML00; + geomDCML00 << "//composition[@name='DCML00']/posXYZ[@volume='DCBR" + << std::setfill('0') << std::setw(2) << i << "']/@X_Y_Z"; + jgeom->Get(geomDCML00.str(), DCBR_XYZ); + DIRC_BAR_Y[i] = (DCML00_XYZ[1] + DCBR_XYZ[1]) * cm; + DIRC_LUT_X[i] = (DIRC[0] + DRCC[0] + DCML00_XYZ[0] + WNGL00_XYZ[0] - DIRC_OWDG_DZ) * cm; + } + } + } + + if (user_opts->Find("DIRCLED", dircledpars)) { + extern int run_number; + extern jana::JApplication *japp; + if (japp == 0) { + G4cerr << "Error in GlueXPrimaryGeneratorAction constructor - " + << "jana global DApplication object not set, " + << "cannot continue." << G4endl; + exit(-1); + } + jana::JGeometry *jgeom = japp->GetJGeometry(run_number); + if (japp == 0) { // dummy + jgeom = 0; + G4cout << "DIRC: ALL parameters loaded from ccdb" << G4endl; + } + vectorDIRC; + vectorDRCC; + vectorOBCS_XYZ; + vectorOBCN_XYZ; + vectorMRAN_XYZ; + vectorMRAS_XYZ; + vectorWM1N_XYZ; + vectorWM1S_XYZ; + vectorWM1N_BOX_XYZ; + vectorWM1S_BOX_XYZ; + + jgeom->Get("//section/composition/posXYZ[@volume='DIRC']/@X_Y_Z", DIRC); + jgeom->Get("//composition[@name='DIRC']/posXYZ[@volume='DRCC']/@X_Y_Z", DRCC); + jgeom->Get("//composition[@name='DRCC']/posXYZ[@volume='OBCN']/@X_Y_Z", OBCN_XYZ); + jgeom->Get("//composition[@name='DRCC']/posXYZ[@volume='OBCS']/@X_Y_Z", OBCS_XYZ); + jgeom->Get("//composition[@name='OBCN']/posXYZ[@volume='MRAN']/@X_Y_Z", MRAN_XYZ); + jgeom->Get("//composition[@name='OBCS']/posXYZ[@volume='MRAS']/@X_Y_Z", MRAS_XYZ); + jgeom->Get("//composition[@name='MRAN']/posXYZ[@volume='WM1N']/@X_Y_Z", WM1N_XYZ); + jgeom->Get("//composition[@name='MRAS']/posXYZ[@volume='WM1S']/@X_Y_Z", WM1S_XYZ); + jgeom->Get("//box[@name='WM1N']/@X_Y_Z", WM1N_BOX_XYZ); + jgeom->Get("//box[@name='WM1S']/@X_Y_Z", WM1S_BOX_XYZ); + + DIRC_LED_OBCN_FDTH_X = (DIRC[0] + DRCC[0] + OBCN_XYZ[0] + MRAN_XYZ[0] + WM1N_XYZ[0] + WM1N_BOX_XYZ[0]/2. + 1.27) * cm; + DIRC_LED_OBCS_FDTH_X = (DIRC[0] + DRCC[0] + OBCS_XYZ[0] + MRAS_XYZ[0] + WM1S_XYZ[0] - WM1S_BOX_XYZ[0]/2. - 1.27) * cm; + + DIRC_LED_OBCN_FDTH_Z = (DIRC[2] + DRCC[2] + OBCN_XYZ[2] + MRAN_XYZ[2] + WM1N_XYZ[2] - WM1N_BOX_XYZ[2]/2. ) * cm; + DIRC_LED_OBCS_FDTH_Z = (DIRC[2] + DRCC[2] + OBCS_XYZ[2] + MRAS_XYZ[2] + WM1S_XYZ[2] - WM1S_BOX_XYZ[2]/2. ) * cm; + + DIRC_LED_OBCN_FDTH1_Y = (DIRC[1] + DRCC[1] + OBCN_XYZ[1] + MRAN_XYZ[1] + WM1N_XYZ[1] - WM1N_BOX_XYZ[1]/2. + 17.235932) * cm; + DIRC_LED_OBCN_FDTH2_Y = (DIRC[1] + DRCC[1] + OBCN_XYZ[1] + MRAN_XYZ[1] + WM1N_XYZ[1] - WM1N_BOX_XYZ[1]/2. + 17.235932 + 31.800038 ) * cm; + DIRC_LED_OBCN_FDTH3_Y = (DIRC[1] + DRCC[1] + OBCN_XYZ[1] + MRAN_XYZ[1] + WM1N_XYZ[1] - WM1N_BOX_XYZ[1]/2. + 17.235932 + 31.800038 * 2. ) * cm; + DIRC_LED_OBCS_FDTH4_Y = (DIRC[1] + DRCC[1] + OBCS_XYZ[1] + MRAS_XYZ[1] + WM1S_XYZ[1] + WM1S_BOX_XYZ[1]/2. - 17.235932) * cm; + DIRC_LED_OBCS_FDTH5_Y = (DIRC[1] + DRCC[1] + OBCS_XYZ[1] + MRAS_XYZ[1] + WM1S_XYZ[1] + WM1S_BOX_XYZ[1]/2. - 17.235932 - 31.800038 ) * cm; + DIRC_LED_OBCS_FDTH6_Y = (DIRC[1] + DRCC[1] + OBCS_XYZ[1] + MRAS_XYZ[1] + WM1S_XYZ[1] + WM1S_BOX_XYZ[1]/2. - 17.235932 - 31.800038 * 2. ) * cm; + + } + + } + std::map infile; std::map beampars; std::map kinepars; @@ -92,6 +236,15 @@ GlueXPrimaryGeneratorAction::GlueXPrimaryGeneratorAction() } fHDDMistream = new hddm_s::istream(*fHDDMinfile); G4cout << "Opened input file: " << infile[1] << G4endl; + std::map skippars; + if (user_opts->Find("SKIP", skippars)) + { + if (skippars[1] > 0) + { + fHDDMistream->skip(skippars[1]); + G4cout << "skipped first " << skippars[1] << " input events." << G4endl; + } + } fPrimaryGenerator = new GlueXPrimaryGenerator(fHDDMistream); fSourceType = SOURCE_TYPE_HDDM; } @@ -101,6 +254,42 @@ GlueXPrimaryGeneratorAction::GlueXPrimaryGeneratorAction() fSourceType = SOURCE_TYPE_COBREMS_GEN; } + else if (user_opts->Find("DIRCLUT", dirclutpars)) + { + fGunParticle.geantType = 0; + fGunParticle.pdgType = 999999; + fGunParticle.partDef = fParticleTable->FindParticle("opticalphoton"); + fGunParticle.deltaR = 0; + fGunParticle.deltaZ = 0; + fGunParticle.mom = 3.18 * eV; + + fGunParticle.deltaMom = 0; + fGunParticle.deltaTheta = 0; + fGunParticle.deltaPhi = 0; + fParticleGun->SetParticleDefinition(fGunParticle.partDef); + + fSourceType = SOURCE_TYPE_PARTICLE_GUN; + } + + else if (user_opts->Find("DIRCLED", dircledpars)) + { + fGunParticle.geantType = 0; + fGunParticle.pdgType = 999999; + fGunParticle.partDef = fParticleTable->FindParticle("opticalphoton"); + fGunParticle.deltaR = 0; + fGunParticle.deltaZ = 0; + fGunParticle.mom = 3.0613 * eV; + + fGunParticle.deltaMom = 0; + fGunParticle.deltaTheta = 0; + fGunParticle.deltaPhi = 0; + fParticleGun->SetParticleDefinition(fGunParticle.partDef); + + fSourceType = SOURCE_TYPE_PARTICLE_GUN; + } + + + else if (user_opts->Find("KINE", kinepars)) { if (kinepars[1] == 1000) { @@ -113,6 +302,11 @@ GlueXPrimaryGeneratorAction::GlueXPrimaryGeneratorAction() fGunParticle.pdgType = 999999; fGunParticle.partDef = fParticleTable->FindParticle("chargedgeantino"); } + else if (kinepars[1] == 1050) { + fGunParticle.geantType = 0; + fGunParticle.pdgType = 999999; + fGunParticle.partDef = fParticleTable->FindParticle("opticalphoton"); + } else { if (kinepars[1] > 100) fGunParticle.geantType = kinepars[1] - 100; @@ -153,7 +347,7 @@ GlueXPrimaryGeneratorAction::GlueXPrimaryGeneratorAction() } fGunParticle.tlogOption = 0; std::map tlogpars; - if (user_opts->Find("PLOG", tlogpars)) { + if (user_opts->Find("TLOG", tlogpars)) { fGunParticle.tlogOption = tlogpars[1]; } @@ -176,15 +370,18 @@ GlueXPrimaryGeneratorAction::GlueXPrimaryGeneratorAction() } if (user_opts->Find("BEAM", beampars)) { - double beamE0 = beampars[1]; - double beamEpeak = beampars[2]; - double beamEmin = (beampars[3] > 0)? beampars[3] : 0.120; - double radColDist = (beampars[4] > 0)? beampars[4] : 76.; - double colDiam = (beampars[5] > 0)? beampars[5] : 0.0034; - double beamEmit = (beampars[6] > 0)? beampars[6] : 2.5e-9; - double radThick = (beampars[7] > 0)? beampars[7] : 20e-6; - - if (beamE0 == 0 || beamEpeak == 0) { + double beamE0 = beampars[1] * GeV; + double beamEpeak = beampars[2] * GeV; + double beamEmin = ((beampars[3] > 0)? beampars[3] : 0.120) * GeV; + double radColDist = ((beampars[4] > 0)? beampars[4] : 76.) * m; + double colDiam = ((beampars[5] > 0)? beampars[5] : 0.0034) * m; + double beamEmit = ((beampars[6] > 0)? beampars[6] : 2.5e-9) * m; + double radThick = ((beampars[7] > 0)? beampars[7] : 20e-6) * m; + double spotRMS = ((beampars[8] > 0)? beampars[8] : 5e-4) * m; + double spotX = ((beampars[9] != 0)? beampars[9] : 0) * m; + double spotY = ((beampars[10] != 0)? beampars[10] : 0) * m; + + if (beamE0 == 0) { G4cerr << "GlueXPrimaryGeneratorAction error: " << "BEAM card specified in control.in but required values " << "Emax and/or Epeak are missing, cannot continue." @@ -199,13 +396,15 @@ GlueXPrimaryGeneratorAction::GlueXPrimaryGeneratorAction() // time : s // current: microAmps - fCobremsGeneration = new CobremsGeneration(beamE0, beamEpeak); - fCobremsGeneration->setPhotonEnergyMin(beamEmin); - fCobremsGeneration->setCollimatorDistance(radColDist); - fCobremsGeneration->setCollimatorDiameter(colDiam); - fCobremsGeneration->setBeamEmittance(beamEmit); - fCobremsGeneration->setTargetThickness(radThick); + fCobremsGeneration = new CobremsGeneration(beamE0/GeV, beamEpeak/GeV); + fCobremsGeneration->setPhotonEnergyMin(beamEmin/GeV); + fCobremsGeneration->setCollimatorDistance(radColDist/m); + fCobremsGeneration->setCollimatorDiameter(colDiam/m); + fCobremsGeneration->setBeamEmittance(beamEmit/(m*radian)); + fCobremsGeneration->setTargetThickness(radThick/m); + fCobremsGeneration->setCollimatorSpotrms(spotRMS/m); fPhotonBeamGenerator = new GlueXPhotonBeamGenerator(fCobremsGeneration); + fPhotonBeamGenerator->setBeamOffset(spotX, spotY); std::map bgratepars; std::map bggatepars; @@ -323,6 +522,12 @@ void GlueXPrimaryGeneratorAction::GeneratePrimariesParticleGun(G4Event* anEvent) // our own derived class. (Sheesh!!) fParticleGun->Reset(); + // std::cout<<"GlueXPrimaryGeneratorAction:: GENERATE PRIMARIES PARTICLE GUN"< dirclutpars; + std::map dircledpars; + // place and smear the particle gun origin G4ThreeVector pos(fGunParticle.pos); if (fGunParticle.deltaR > 0) { @@ -361,8 +566,8 @@ void GlueXPrimaryGeneratorAction::GeneratePrimariesParticleGun(G4Event* anEvent) } if (fGunParticle.deltaTheta > 0) { if (fGunParticle.plogOption) { - double thetamin = thetap - fGunParticle.deltaMom / 2; - double thetamax = thetap + fGunParticle.deltaMom / 2; + double thetamin = thetap - fGunParticle.deltaTheta / 2; + double thetamax = thetap + fGunParticle.deltaTheta / 2; thetamin = (thetamin > 0)? thetamin : 1e-6*degree; thetap = thetamin * pow(thetamax/thetamin, G4UniformRand()); } @@ -372,11 +577,212 @@ void GlueXPrimaryGeneratorAction::GeneratePrimariesParticleGun(G4Event* anEvent) } if (fGunParticle.deltaPhi > 0) phip += (G4UniformRand() - 0.5) * fGunParticle.deltaPhi; + + // Special case of Cherenkov photon gun for DIRC Look Up Tables (LUT) + if (user_opts->Find("DIRCLUT", dirclutpars)) { + + // array of bar y-positions for LUT from JGeometry + double y = 0.; // no shift + double x = DIRC_LUT_X[dirclutpars[1]]; + double z = DIRC_LUT_Z; + + G4ThreeVector vec(0,0,1); + double rand1 = G4UniformRand(); + double rand2 = G4UniformRand(); + vec.setTheta(acos(rand1)); + vec.setPhi(2*M_PI*rand2); + vec.rotateY(M_PI/2.); + y = DIRC_BAR_Y[dirclutpars[1]]; + if (dirclutpars[1] < 24) { + vec.rotateY(M_PI); + } + + // spread over end of bar in y and z + y += DIRC_QZBL_DY/2.0 - DIRC_QZBL_DY*G4UniformRand(); + z += DIRC_QZBL_DZ/2.0 - DIRC_QZBL_DZ*G4UniformRand(); + + thetap = vec.theta(); + phip = vec.phi(); + fParticleGun->SetParticlePosition(G4ThreeVector(x,y,z)); + } + + + + double DeltaT = 0.; + // Special case of Cherenkov photon gun for DIRC LED generator + if (user_opts->Find("DIRCLED", dircledpars)){ + + double x(0.),y(0.),z(0.); + + int FDTH = -1; + vector FDTHs = {}; + for (int par_index = 1; par_index <= 6; par_index++) + { + int passed_FDTH = dircledpars[par_index]; + if (passed_FDTH && 0 < passed_FDTH && passed_FDTH < 7) + FDTHs.push_back(dircledpars[par_index]); + } + int NumFDTHs = int(FDTHs.size()); + double rand0 = G4UniformRand(); + for (int FDTH_index = 0; FDTH_index < NumFDTHs; FDTH_index++) + { + if (rand0 <= (FDTH_index+1)*(1./NumFDTHs)) + { + FDTH = FDTHs[FDTH_index]; break; + } + else + continue; + } + + switch (FDTH) + { + case 1: + x = DIRC_LED_OBCN_FDTH_X; + y = DIRC_LED_OBCN_FDTH1_Y; + z = DIRC_LED_OBCN_FDTH_Z; + break; + + case 2: + x = DIRC_LED_OBCN_FDTH_X; + y = DIRC_LED_OBCN_FDTH2_Y; + z = DIRC_LED_OBCN_FDTH_Z; + break; + + case 3: + x = DIRC_LED_OBCN_FDTH_X; + y = DIRC_LED_OBCN_FDTH3_Y; + z = DIRC_LED_OBCN_FDTH_Z; + break; + + case 4: + x = DIRC_LED_OBCS_FDTH_X; + y = DIRC_LED_OBCS_FDTH4_Y; + z = DIRC_LED_OBCS_FDTH_Z; + break; + + case 5: + x = DIRC_LED_OBCS_FDTH_X; + y = DIRC_LED_OBCS_FDTH5_Y; + z = DIRC_LED_OBCS_FDTH_Z; + break; + + case 6: + x = DIRC_LED_OBCS_FDTH_X; + y = DIRC_LED_OBCS_FDTH6_Y; + z = DIRC_LED_OBCS_FDTH_Z; + break; + + default: + break; + } + + //z -= 0.5*cm; + double theta_range = 12.5; // in degrees + double inclination_wrt_bars_deg = 0.;//negative->away from 3-segment mirror; positive->towards 3-segment mirror + double angle_towards_center_deg = 0.;//bending angle for the two feedthroughs on the sides towards the center + + if (x > 0.) + inclination_wrt_bars_deg *= -1.; + if (FDTH == 3 || FDTH == 4) + angle_towards_center_deg *= -1.; + if (FDTH == 2 || FDTH == 5) + angle_towards_center_deg = 0.; + + G4ThreeVector vec(0,0,1); + double rand1 = G4UniformRand(); + double rand2 = G4UniformRand(); + + double costheta = -1. + rand1 * (std::cos((180.-theta_range) * M_PI / 180.) + 1.); + + double rand3 = G4UniformRand(); + double theta_to_set = acos(costheta); + if (rand3 < 0.5) + theta_to_set = 2*M_PI - theta_to_set; + + vec.setTheta(theta_to_set); + vec.setPhi(2*M_PI*rand2); + vec.rotateY(inclination_wrt_bars_deg*deg); + vec.rotateX(angle_towards_center_deg*deg); +/* + //For square diffuser case + double theta_range = 25.; // in degrees + double diffuser_X = 1.697 * cm; + double diffuser_Y = 1.697 * cm; + double inclination_wrt_bars_deg = -6.; + + G4ThreeVector vec(0,0,-1.); + double rand1 = G4UniformRand(); + double rand2 = G4UniformRand(); + double a = 2.* tan(theta_range*M_PI/180.); + vec.setX((rand1-0.5)*a); + vec.setY((rand2-0.5)*a); + vec.setZ(-1.); + + double diffuser_offset_x = diffuser_X/2. - diffuser_X * G4UniformRand(); + double diffuser_offset_y = diffuser_Y/2. - diffuser_Y * G4UniformRand(); + + G4ThreeVector diffuser_offset_vec(diffuser_offset_x,diffuser_offset_y,0.); + diffuser_offset_vec.rotateY(inclination_wrt_bars_deg*deg); + + x += diffuser_offset_vec.x(); + y += diffuser_offset_vec.y(); + z += diffuser_offset_vec.z(); + +*/ + + // time smearing from LED pulse shape + double t_rise = 0.84; + double t_FWHM = 1.5; + + double t_range_LED = t_rise + t_FWHM; + double t_rand1 = G4UniformRand(); + double t_rand2 = G4UniformRand(); + double t_LEDShape = t_rand1 * t_range_LED; + + double pulse_val = -1.; + while (t_rand2 > pulse_val) + { + t_rand1 = G4UniformRand(); + t_rand2 = G4UniformRand(); + t_LEDShape = t_rand1 * t_range_LED; + + if (0.<= t_LEDShape && t_LEDShape < t_rise) + pulse_val = 1./t_rise * t_LEDShape; + else if (t_rise <= t_LEDShape && t_LEDShape < t_FWHM) + pulse_val = 1.; + else if (t_FWHM <= t_LEDShape && t_LEDShape < t_range_LED) + pulse_val = -1./t_rise * t_LEDShape + 1./t_rise * t_range_LED; + else + pulse_val = 0.; + + if (t_rand2 <= pulse_val) + break; + } + double DeltaT_LED = t_LEDShape; + + + // delay from LED feedthrough cables + double DeltaT_CableDelay = 0.; + if (FDTH == 2 || FDTH == 5) + DeltaT_CableDelay = 10.; + if (FDTH == 3 || FDTH == 6) + DeltaT_CableDelay = 20.; + + + DeltaT = DeltaT_LED + DeltaT_CableDelay; + + G4ThreeVector pos_vec(x,y,z); + thetap = vec.theta(); + phip = vec.phi(); + fParticleGun->SetParticlePosition(pos_vec); + + } + G4ThreeVector mom(p * sin(thetap) * cos(phip), p * sin(thetap) * sin(phip), p * cos(thetap)); fParticleGun->SetParticleMomentum(mom); - fParticleGun->SetParticleTime(0); + fParticleGun->SetParticleTime(0.+DeltaT); // Set the event number and fire the gun anEvent->SetEventID(++fEventCount); @@ -397,7 +803,7 @@ void GlueXPrimaryGeneratorAction::GeneratePrimariesHDDM(G4Event* anEvent) if (fPrimaryGenerator != 0) { double beamDiameter = GlueXPhotonBeamGenerator::getBeamDiameter(); double beamVelocity = GlueXPhotonBeamGenerator::getBeamVelocity(); - double x, y, z, t; + double x, y; while (true) { x = G4UniformRand() - 0.5; y = G4UniformRand() - 0.5; @@ -407,18 +813,26 @@ void GlueXPrimaryGeneratorAction::GeneratePrimariesHDDM(G4Event* anEvent) break; } } - z = fTargetCenterZ + (G4UniformRand() - 0.5) * fTargetLength; + double z = fTargetCenterZ + (G4UniformRand() - 0.5) * fTargetLength; + double ttag = GlueXPhotonBeamGenerator::GenerateTriggerTime(anEvent); + double trel = (z - fRFreferencePlaneZ) / beamVelocity; fPrimaryGenerator->SetParticlePosition(G4ThreeVector(x,y,z)); - t = (z - fTargetCenterZ) / beamVelocity; - t -= GlueXPhotonBeamGenerator::GenerateTriggerTime(anEvent); - fPrimaryGenerator->SetParticleTime(t); + fPrimaryGenerator->SetParticleTime(trel + ttag); fPrimaryGenerator->GeneratePrimaryVertex(anEvent); - GlueXPhotonBeamGenerator::GenerateRFsync(anEvent); GlueXUserEventInformation *eventinfo; eventinfo = (GlueXUserEventInformation*)anEvent->GetUserInformation(); if (eventinfo) { + // The above-assigned vertex coordinates and time are advisory to + // GeneratePrimaryVertex, and may have been overridden by values + // read from the input MC event record. + G4PrimaryVertex *vertex = anEvent->GetPrimaryVertex(); + trel = (vertex->GetZ0() - fRFreferencePlaneZ) / beamVelocity; + ttag = vertex->GetT0() - trel; double E = eventinfo->GetBeamPhotonEnergy(); - GlueXPhotonBeamGenerator::GenerateTaggerHit(anEvent, E, t); + GlueXPhotonBeamGenerator::GenerateTaggerHit(anEvent, E, ttag); + } + else { + return; } } ++fEventCount; @@ -477,30 +891,111 @@ int GlueXPrimaryGeneratorAction::ConvertGeant3ToPdg(int Geant3type) case 24 : return 3334; // Omega- (PB) case 25 : return -2112; // anti-neutron case 26 : return -3122; // anti-Lambda - case 27 : return -3222; // Sigma- - case 28 : return -3212; // Sigma0 - case 29 : return -3112; // Sigma+ (PB)*/ - case 30 : return -3322; // Xi0 - case 31 : return -3312; // Xi+ - case 32 : return -3334; // Omega+ (PB) - case 33 : return -15; // tau+ - case 34 : return 15; // tau- - case 35 : return 411; // D+ - case 36 : return -411; // D- - case 37 : return 421; // D0 - case 38 : return -421; // D0 - case 39 : return 431; // Ds+ - case 40 : return -431; // anti Ds- - case 41 : return 4122; // Lamba_c+ - case 42 : return 24; // W+ - case 43 : return -24; // W- - case 44 : return 23; // Z + case 27 : return -3222; // anti-Sigma- + case 28 : return -3212; // anti-Sigma0 + case 29 : return -3112; // anti-Sigma+ + case 30 : return -3322; // anti-Xi0 + case 31 : return -3312; // anti-Xi+ + case 32 : return -3334; // anti-Omega+ case 45 : return 1000010020; // deuteron case 46 : return 1000010030; // triton case 47 : return 1000020040; // alpha case 48 : return 0; // geantino (no PDG type) case 49 : return 1000020030; // He3 ion case 50 : return 0; // Cerenkov photon (no PDG type) + case 61 : return 1000030060; // Li6 + case 62 : return 1000030070; // Li7 + case 63 : return 1000040070; // Be7 + case 64 : return 1000040090; // Be9 + case 65 : return 1000050100; // B10 + case 66 : return 1000050110; // B11 + case 67 : return 1000060120; // C12 + case 68 : return 1000070140; // N14 + case 69 : return 1000080160; // O16 + case 70 : return 1000090190; // F19 + case 71 : return 1000100200; // Ne20 + case 72 : return 1000110230; // Na23 + case 73 : return 1000120240; // Mg24 + case 74 : return 1000130270; // Al27 + case 75 : return 1000140280; // Si28 + case 76 : return 1000150310; // P31 + case 77 : return 1000160320; // S32 + case 78 : return 1000170350; // Cl35 + case 79 : return 1000180360; // Ar36 + case 80 : return 1000190390; // K39 + case 81 : return 1000200400; // Ca40 + case 82 : return 1000210450; // Sc45 + case 83 : return 1000220480; // Ti48 + case 84 : return 1000230510; // V51 + case 85 : return 1000240520; // Cr52 + case 86 : return 1000250550; // Mn55 + case 87 : return 1000260560; // Fe56 + case 88 : return 1000270590; // Co59 + case 89 : return 1000280580; // Ni58 + case 90 : return 1000290630; // Cu63 + case 91 : return 1000300640; // Zn64 + case 92 : return 1000320740; // Ge74 + case 93 : return 1000340800; // Se80 + case 94 : return 1000360840; // Kr84 + case 95 : return 1000380880; // Sr88 + case 96 : return 1000400900; // Zr90 + case 97 : return 1000420980; // Mo98 + case 98 : return 1000461060; // Pd106 + case 99 : return 1000481140; // Cd114 + case 100 : return 1000501200; // Sn120 + case 101 : return 1000541320; // Xe132 + case 102 : return 1000561380; // Ba138 + case 103 : return 1000581400; // Ce140 + case 104 : return 1000621520; // Sm152 + case 105 : return 1000661640; // Dy164 + case 106 : return 1000701740; // Yb174 + case 107 : return 1000741840; // W184 + case 108 : return 1000781940; // Pt194 + case 109 : return 1000791970; // Au197 + case 110 : return 1000802020; // Hg202 + case 111 : return 1000822080; // Pb208 + case 112 : return 1000922380; // U238 + + // These are "private" Geant3 types that were defined in hdgeant + case 33 : return 223; // omega(782) + case 34 : return 333; // phi(1020) + case 35 : return 331; // etaPrime(958) + case 36 : return 0; // unused + case 37 : return 0; // unused + case 38 : return 0; // unused + case 39 : return 0; // unused + case 40 : return 0; // unused + case 41 : return 0; // unused + case 42 : return 213; // rho(770)+ + case 43 : return -213; // rho(770)- + case 44 : return 113; // rho(770)0 + + case 182 : return 2224; // Delta++ + case 183 : return 443; // Jpsi + case 184 : return 441; // Eta_c + case 185 : return 10441; // Chi_c0 + case 186 : return 20443; // Chi_c1 + case 187 : return 445; // Chi_c2 + case 188 : return 100443; // Psi2s + case 189 : return 421; // D0 + case 190 : return 411; // D+ + case 191 : return 10421; // Dstar0 + case 192 : return 10411; // Dstar+ + case 193 : return 4022; // Lambda_c+ + case 194 : return -421; // anti-D0 + + case 163 : return 9000111; // a0(980) + case 164 : return 9010221; // f0(980) + case 165 : return 313; // K*(892)0 + case 166 : return 323; // K*(892)+ + case 167 : return -323; // K*(892)- + case 168 : return -313; // anti-K*(892)0 + case 169 : return 20323; // K1(1400)+ + case 170 : return -20323; // K1(1400)- + case 171 : return 4122; // b1(1235)+ + case 172 : return 3224; // Sigma*(1385)+ + case 173 : return 3214; // Sigma*(1385)0 + case 174 : return 3114; // Sigma*(1385)- default : G4cout << "Warning in GlueXPrimaryGeneratorAction::" @@ -547,31 +1042,106 @@ int GlueXPrimaryGeneratorAction::ConvertPdgToGeant3(int PDGtype) case 3112 : return 21; // Sigma- case 3322 : return 22; // Xi0 case 3312 : return 23; // Xi- - case 3334 : return 24; // Omega- (PB) + case 3334 : return 24; // Omega- case -2112 : return 25; // anti-neutron case -3122 : return 26; // anti-Lambda case -3222 : return 27; // Sigma- case -3212 : return 28; // Sigma0 - case -3112 : return 29; // Sigma+ (PB)*/ + case -3112 : return 29; // Sigma+ case -3322 : return 30; // Xi0 case -3312 : return 31; // Xi+ - case -3334 : return 32; // Omega+ (PB) - case -15 : return 33; // tau+ - case 15 : return 34; // tau- - case 411 : return 35; // D+ - case -411 : return 36; // D- - case 421 : return 37; // D0 - case -421 : return 38; // D0 - case 431 : return 39; // Ds+ - case -431 : return 40; // anti Ds- - case 4122 : return 41; // Lamba_c+ - case 24 : return 42; // W+ - case -24 : return 43; // W- - case 23 : return 44; // Z + case -3334 : return 32; // Omega+ case 1000010020 : return 45; // deuteron case 1000010030 : return 46; // triton case 1000020040 : return 47; // alpha - case 1000020030 : return 49; // He3 ion + case 1000020030 : return 49; // He3 + case 1000030060 : return 61; // Li6 + case 1000030070 : return 62; // Li7 + case 1000040070 : return 63; // Be7 + case 1000040090 : return 64; // Be9 + case 1000050100 : return 65; // B10 + case 1000050110 : return 66; // B11 + case 1000060120 : return 67; // C12 + case 1000070140 : return 68; // N14 + case 1000080160 : return 69; // O16 + case 1000090190 : return 70; // F19 + case 1000100200 : return 71; // Ne20 + case 1000110230 : return 72; // Na23 + case 1000120240 : return 73; // Mg24 + case 1000130270 : return 74; // Al27 + case 1000140280 : return 75; // Si28 + case 1000150310 : return 76; // P31 + case 1000160320 : return 77; // S32 + case 1000170350 : return 78; // Cl35 + case 1000180360 : return 79; // Ar36 + case 1000190390 : return 80; // K39 + case 1000200400 : return 81; // Ca40 + case 1000210450 : return 82; // Sc45 + case 1000220480 : return 83; // Ti48 + case 1000230510 : return 84; // V51 + case 1000240520 : return 85; // Cr52 + case 1000250550 : return 86; // Mn55 + case 1000260560 : return 87; // Fe56 + case 1000270590 : return 88; // Co59 + case 1000280580 : return 89; // Ni58 + case 1000290630 : return 90; // Cu63 + case 1000300640 : return 91; // Zn64 + case 1000320740 : return 92; // Ge74 + case 1000340800 : return 93; // Se80 + case 1000360840 : return 94; // Kr84 + case 1000380880 : return 95; // Sr88 + case 1000400900 : return 96; // Zr90 + case 1000420980 : return 97; // Mo98 + case 1000461060 : return 98; // Pd106 + case 1000481140 : return 99; // Cd114 + case 1000501200 : return 100; // Sn120 + case 1000541320 : return 101; // Xe132 + case 1000561380 : return 102; // Ba138 + case 1000581400 : return 103; // Ce140 + case 1000621520 : return 104; // Sm152 + case 1000661640 : return 105; // Dy164 + case 1000701740 : return 106; // Yb174 + case 1000741840 : return 107; // W184 + case 1000781940 : return 108; // Pt194 + case 1000791970 : return 109; // Au197 + case 1000802020 : return 110; // Hg202 + case 1000822080 : return 111; // Pb208 + case 1000922380 : return 112; // U238 + + // These are "private" Geant3 types that were defined in hdgeant + case 223 : return 33; // omega(782) + case 333 : return 34; // phi(1020) + case 331 : return 35; // etaPrime(958) + case 213 : return 42; // rho(770)+ + case -213 : return 43; // rho(770)- + case 113 : return 44; // rho(770)0 + + case 2224 : return 182; // Delta++ + case 443 : return 183; // Jpsi + case 441 : return 184; // Eta_c + case 10441 : return 185; // Chi_c0 + case 20443 : return 186; // Chi_c1 + case 445 : return 187; // Chi_c2 + case 100443 : return 188; // Psi2s + case 421 : return 189; // D0 + case 411 : return 190; // D+ + case 10421 : return 191; // Dstar0 + case 10411 : return 192; // Dstar+ + case 4022 : return 193; // Lambda_c+ + case -421 : return 194; // anti-D0 + + case 9000111 : return 163; // a0(980) + case 9010221 : return 164; // f0(980) + case 313 : return 165; // K*(892)0 + case 323 : return 166; // K*(892)+ + case -323 : return 167; // K*(892)- + case -313 : return 168; // anti-K*(892)0 + case 20323 : return 169; // K1(1400)+ + case -20323 : return 170; // K1(1400)- + case 4122 : return 171; // b1(1235)+ + case 3224 : return 172; // Sigma*(1385)+ + case 3214 : return 173; // Sigma*(1385)0 + case 3114 : return 174; // Sigma*(1385)- default : if (PDGtype < 1000000000) { @@ -593,3 +1163,32 @@ double GlueXPrimaryGeneratorAction::GetMass(int Geant3Type) { return GetMassPDG(ConvertGeant3ToPdg(Geant3Type)); } + +G4ParticleDefinition *GlueXPrimaryGeneratorAction::GetParticle(int PDGtype) +{ + G4ParticleDefinition *p = fParticleTable->FindParticle(PDGtype); + if (p==0) { + if (PDGtype > 1000000000) { + p = fParticleTable->GetIonTable()->GetIon(PDGtype); + } + else { + G4cout << "unknown particle type " << PDGtype + << ", substituting geantino in its place!" + << G4endl; + p = fParticleTable->FindParticle("geantino"); + } + } + return p; +} + +G4ParticleDefinition *GlueXPrimaryGeneratorAction::GetParticle(const G4String &name) +{ + G4ParticleDefinition *p = fParticleTable->FindParticle(name); + if (p==0) { + G4cout << "unknown particle type " << name + << ", substituting geantino in its place!" + << G4endl; + p = fParticleTable->FindParticle("geantino"); + } + return p; +} diff --git a/src/GlueXPrimaryGeneratorAction.hh b/src/GlueXPrimaryGeneratorAction.hh index 2a3a7b9..79b8941 100644 --- a/src/GlueXPrimaryGeneratorAction.hh +++ b/src/GlueXPrimaryGeneratorAction.hh @@ -21,11 +21,13 @@ #include "GlueXPrimaryGenerator.hh" #include "G4ParticleDefinition.hh" #include "G4ParticleTable.hh" +#include "G4IonTable.hh" #include "G4AutoLock.hh" #include "GlueXParticleGun.hh" #include "G4Event.hh" #include +#include #include @@ -95,6 +97,7 @@ class GlueXPrimaryGeneratorAction : public G4VUserPrimaryGeneratorAction static double fBeamBackgroundGateStart; static double fBeamBackgroundGateStop; static double fL1triggerTimeSigma; + static double fRFreferencePlaneZ; static int fEventCount; @@ -128,6 +131,12 @@ class GlueXPrimaryGeneratorAction : public G4VUserPrimaryGeneratorAction static double getL1triggerTimeSigma() { return fL1triggerTimeSigma; } + static void setRFreferencePlaneZ(double refZ) { + fRFreferencePlaneZ = refZ; + } + static double getRFreferencePlaneZ() { + return fRFreferencePlaneZ; + } int getEventCount() const { return fEventCount; } @@ -135,16 +144,13 @@ class GlueXPrimaryGeneratorAction : public G4VUserPrimaryGeneratorAction private: static G4Mutex fMutex; static std::list fInstance; -}; + double DIRC_LUT_X[48], DIRC_BAR_Y[48]; + double DIRC_LUT_Z; + double DIRC_QZBL_DY, DIRC_QZBL_DZ, DIRC_OWDG_DZ; + double DIRC_LED_OBCS_FDTH_X, DIRC_LED_OBCS_FDTH_Z, DIRC_LED_OBCN_FDTH_X, DIRC_LED_OBCN_FDTH_Z; + double DIRC_LED_OBCN_FDTH1_Y, DIRC_LED_OBCN_FDTH2_Y, DIRC_LED_OBCN_FDTH3_Y; + double DIRC_LED_OBCS_FDTH4_Y, DIRC_LED_OBCS_FDTH5_Y, DIRC_LED_OBCS_FDTH6_Y; -inline G4ParticleDefinition *GlueXPrimaryGeneratorAction::GetParticle(int PDGtype) -{ - return fParticleTable->FindParticle(PDGtype); -} - -inline G4ParticleDefinition *GlueXPrimaryGeneratorAction::GetParticle(const G4String &name) -{ - return fParticleTable->FindParticle(name); -} +}; #endif diff --git a/src/GlueXPseudoDetectorTAG.cc b/src/GlueXPseudoDetectorTAG.cc index 636554c..f5eb3db 100644 --- a/src/GlueXPseudoDetectorTAG.cc +++ b/src/GlueXPseudoDetectorTAG.cc @@ -145,7 +145,7 @@ int GlueXPseudoDetectorTAG::addTaggerPhoton(const G4Event *event, G4VUserEventInformation* info = event->GetUserInformation(); hddm_s::HDDM *record = ((GlueXUserEventInformation*)info)->getOutputRecord(); if (record == 0) { - G4cerr << "GlueXPseudoDetectorTAG::addTaggerHit error - " + G4cerr << "GlueXPseudoDetectorTAG::addTaggerPhoton error - " << "hits seen but no output hddm record to save them into, " << "cannot continue!" << G4endl; exit(1); diff --git a/src/GlueXRunAction.cc b/src/GlueXRunAction.cc index 9744c20..a4deec7 100644 --- a/src/GlueXRunAction.cc +++ b/src/GlueXRunAction.cc @@ -26,7 +26,7 @@ void GlueXRunAction::BeginOfRunAction(const G4Run*) std::map save; if (user_opts->Find("SAVEHITS", save)) { - GlueXUserEventInformation::fWriteNoHitEvents = (save[1] != 0); + GlueXUserEventInformation::fWriteNoHitEvents |= (save[1] != 0); } fPhysicsList->SelectActiveProcesses(1); diff --git a/src/GlueXSensitiveDetectorBCAL.cc b/src/GlueXSensitiveDetectorBCAL.cc index c569095..ebb2ffb 100644 --- a/src/GlueXSensitiveDetectorBCAL.cc +++ b/src/GlueXSensitiveDetectorBCAL.cc @@ -20,6 +20,8 @@ #include +#define USE_ENERGY_WEIGHTED_TIMES 1 + // Cutoff on the total number of allowed hits int GlueXSensitiveDetectorBCAL::MAX_HITS = 100; @@ -44,8 +46,6 @@ double GlueXSensitiveDetectorBCAL::THRESH_MEV = 1.; int GlueXSensitiveDetectorBCAL::instanceCount = 0; G4Mutex GlueXSensitiveDetectorBCAL::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorBCAL::fVolumeTable; - GlueXSensitiveDetectorBCAL::GlueXSensitiveDetectorBCAL(const G4String& name) : G4VSensitiveDetector(name), fCellsMap(0), fPointsMap(0) @@ -93,12 +93,14 @@ GlueXSensitiveDetectorBCAL::GlueXSensitiveDetectorBCAL( : G4VSensitiveDetector(src), fCellsMap(src.fCellsMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorBCAL &GlueXSensitiveDetectorBCAL::operator=(const GlueXSensitiveDetectorBCAL &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fCellsMap = src.fCellsMap; fPointsMap = src.fPointsMap; @@ -107,12 +109,13 @@ GlueXSensitiveDetectorBCAL &GlueXSensitiveDetectorBCAL::operator=(const GlueXSensitiveDetectorBCAL::~GlueXSensitiveDetectorBCAL() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorBCAL::Initialize(G4HCofThisEvent* hce) { - fCellsMap = new + fCellsMap = new GlueXHitsMapBCALcell(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapBCALpoint(SensitiveDetectorName, collectionName[1]); @@ -122,7 +125,7 @@ void GlueXSensitiveDetectorBCAL::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorBCAL::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* RHhist) { double dEsum = step->GetTotalEnergyDeposit(); const G4ThreeVector &pin = step->GetPreStepPoint()->GetMomentum(); @@ -163,21 +166,21 @@ G4bool GlueXSensitiveDetectorBCAL::ProcessHits(G4Step* step, xin[0] * pin[0] + xin[1] * pin[1] > 0 && Ein > THRESH_MEV*MeV) { - GlueXHitBCALpoint* newPoint = new GlueXHitBCALpoint(); + GlueXHitBCALpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.z_cm = xin[2]/cm; + newPoint.r_cm = xin.perp()/cm; + newPoint.phi_rad = xin.phi(); + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; G4int key = fPointsMap->entries(); fPointsMap->add(key, newPoint); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->z_cm = xin[2]/cm; - newPoint->r_cm = xin.perp()/cm; - newPoint->phi_rad = xin.phi(); - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; trackinfo->SetGlueXHistory(1); // The original HDGeant hits code for the BCal had a heavy-weight @@ -228,11 +231,12 @@ G4bool GlueXSensitiveDetectorBCAL::ProcessHits(G4Step* step, int key = GlueXHitBCALcell::GetKey(module, layer, sector); GlueXHitBCALcell *cell = (*fCellsMap)[key]; if (cell == 0) { - cell = new GlueXHitBCALcell(module, layer, sector); - fCellsMap->add(key, cell); + GlueXHitBCALcell newcell(module, layer, sector); + fCellsMap->add(key, newcell); + cell = (*fCellsMap)[key]; } - // Add the hit to the hits vector, maintaining strict time ordering + // Add the hit to the bcal truth hits list, maintaining strict time ordering int merge_hit = 0; std::vector::iterator hiter; @@ -247,17 +251,28 @@ G4bool GlueXSensitiveDetectorBCAL::ProcessHits(G4Step* step, } if (merge_hit) { // Use the time from the earlier hit but add the energy deposition - hiter->E_GeV += dEsum/GeV; +#if USE_ENERGY_WEIGHTED_TIMES + hiter->t_ns = (hiter->t_ns * hiter->E_GeV + + t/ns * dEsum/GeV) / + (hiter->E_GeV + dEsum/GeV); + hiter->zlocal_cm = (hiter->zlocal_cm * hiter->E_GeV + + xlocal[2]/cm * dEsum/GeV) / + (hiter->E_GeV + dEsum/GeV); +#else if (hiter->t_ns*ns > t) { hiter->t_ns = t/ns; hiter->zlocal_cm = xlocal[2]/cm; hiter->incidentId_ = trackinfo->GetBCALincidentID(); } +#endif + // correction factor makes shower yields match hdgeant + hiter->E_GeV += dEsum/GeV * 1.015; } else if ((int)cell->hits.size() < MAX_HITS) { // create new hit hiter = cell->hits.insert(hiter, GlueXHitBCALcell::hitinfo_t()); - hiter->E_GeV = dEsum/GeV; + // correction factor makes shower yields match hdgeant + hiter->E_GeV = dEsum/GeV * 1.015; hiter->t_ns = t/ns; hiter->zlocal_cm = xlocal[2]/cm; hiter->incidentId_ = trackinfo->GetBCALincidentID(); @@ -267,6 +282,90 @@ G4bool GlueXSensitiveDetectorBCAL::ProcessHits(G4Step* step, << "max hit count " << MAX_HITS << " exceeded, truncating!" << G4endl; } + + // Add the hit to the upstream sipm hits list, with strict time ordering + + double udist = MODULE_FULL_LENGTH/2 + xlocal[2]; + double dEup = dEsum * exp(-udist/ATTENUATION_LENGTH); + double tup = t + udist / C_EFFECTIVE; + merge_hit = 0; + for (hiter = cell->hits.begin(); hiter != cell->hits.end(); ++hiter) { + if (fabs(hiter->tup_ns*ns - tup) < TWO_HIT_TIME_RESOL) { + merge_hit = 1; + break; + } + else if (hiter->tup_ns*ns > tup) { + break; + } + } + if (merge_hit) { + // Use the time from the earlier hit but add the energy deposition +#if USE_ENERGY_WEIGHTED_TIMES + hiter->tup_ns = (hiter->tup_ns * hiter->Eup_GeV + + tup/ns * dEup/GeV) / + (hiter->Eup_GeV + dEup/GeV); +#else + if (hiter->tup_ns*ns > tup) { + hiter->tup_ns = tup/ns; + } +#endif + // correction factor makes shower yields match hdgeant + hiter->Eup_GeV += dEup/GeV * 1.015; + } + else if ((int)cell->hits.size() < MAX_HITS) { + // create new hit + hiter = cell->hits.insert(hiter, GlueXHitBCALcell::hitinfo_t()); + // correction factor makes shower yields match hdgeant + hiter->Eup_GeV = dEup/GeV * 1.015; + hiter->tup_ns = tup/ns; + } + else { + G4cerr << "GlueXSensitiveDetectorBCAL::ProcessHits error: " + << "max hit count " << MAX_HITS << " exceeded, truncating!" + << G4endl; + } + + // Add the hit to the downstream sipm hits list, with strict time ordering + + double ddist = MODULE_FULL_LENGTH/2 - xlocal[2]; + double dEdown = dEsum * exp(-ddist/ATTENUATION_LENGTH); + double tdown = t + ddist / C_EFFECTIVE; + merge_hit = 0; + for (hiter = cell->hits.begin(); hiter != cell->hits.end(); ++hiter) { + if (fabs(hiter->tdown_ns*ns - tdown) < TWO_HIT_TIME_RESOL) { + merge_hit = 1; + break; + } + else if (hiter->tdown_ns*ns > tdown) { + break; + } + } + if (merge_hit) { + // Use the time from the earlier hit but add the energy deposition +#if USE_ENERGY_WEIGHTED_TIMES + hiter->tdown_ns = (hiter->tdown_ns * hiter->Edown_GeV + + tdown/ns * dEdown/GeV) / + (hiter->Edown_GeV + dEdown/GeV); +#else + if (hiter->tdown_ns*ns > tdown) { + hiter->tdown_ns = tdown/ns; + } +#endif + // correction factor makes shower yields match hdgeant + hiter->Edown_GeV += dEdown/GeV * 1.015; + } + else if ((int)cell->hits.size() < MAX_HITS) { + // create new hit + hiter = cell->hits.insert(hiter, GlueXHitBCALcell::hitinfo_t()); + // correction factor makes shower yields match hdgeant + hiter->Edown_GeV = dEdown/GeV * 1.015; + hiter->tdown_ns = tdown/ns; + } + else { + G4cerr << "GlueXSensitiveDetectorBCAL::ProcessHits error: " + << "max hit count " << MAX_HITS << " exceeded, truncating!" + << G4endl; + } } return true; } @@ -338,6 +437,16 @@ void GlueXSensitiveDetectorBCAL::EndOfEvent(G4HCofThisEvent*) thit(0).setT(hits[ih].t_ns); thit(0).setZLocal(hits[ih].zlocal_cm); thit(0).setIncident_id(hits[ih].incidentId_); + if (hits[ih].Eup_GeV >= THRESH_MEV/1e3) { + hddm_s::BcalSiPMUpHitList uhit = cell(0).addBcalSiPMUpHits(1); + uhit(0).setE(hits[ih].Eup_GeV); + uhit(0).setT(hits[ih].tup_ns); + } + if (hits[ih].Edown_GeV >= THRESH_MEV/1e3) { + hddm_s::BcalSiPMDownHitList dhit = cell(0).addBcalSiPMDownHits(1); + dhit(0).setE(hits[ih].Edown_GeV); + dhit(0).setT(hits[ih].tdown_ns); + } } } } @@ -362,7 +471,7 @@ void GlueXSensitiveDetectorBCAL::EndOfEvent(G4HCofThisEvent*) } int GlueXSensitiveDetectorBCAL::GetIdent(std::string div, - const G4VTouchable *touch) + const G4VTouchable *touch) { const HddsG4Builder* bldr = GlueXDetectorConstruction::GetBuilder(); std::map >::const_iterator iter; @@ -378,10 +487,9 @@ int GlueXSensitiveDetectorBCAL::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorBCAL.hh b/src/GlueXSensitiveDetectorBCAL.hh index fb2ab90..108f182 100644 --- a/src/GlueXSensitiveDetectorBCAL.hh +++ b/src/GlueXSensitiveDetectorBCAL.hh @@ -29,7 +29,7 @@ class GlueXSensitiveDetectorBCAL : public G4VSensitiveDetector virtual ~GlueXSensitiveDetectorBCAL(); virtual void Initialize(G4HCofThisEvent* hitCollection); - virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* unused); + virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* ROhist); virtual void EndOfEvent(G4HCofThisEvent* hitCollection); int GetIdent(std::string div, const G4VTouchable *touch); @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorBCAL : public G4VSensitiveDetector GlueXHitsMapBCALcell* fCellsMap; GlueXHitsMapBCALpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static double THRESH_MEV; diff --git a/src/GlueXSensitiveDetectorCCAL.cc b/src/GlueXSensitiveDetectorCCAL.cc index e2c2fdb..de462cf 100644 --- a/src/GlueXSensitiveDetectorCCAL.cc +++ b/src/GlueXSensitiveDetectorCCAL.cc @@ -24,26 +24,24 @@ int GlueXSensitiveDetectorCCAL::MAX_HITS = 100; // Geometry constants for the CCal -int GlueXSensitiveDetectorCCAL::CENTRAL_ROW = 8; -int GlueXSensitiveDetectorCCAL::CENTRAL_COLUMN = 8; +//int GlueXSensitiveDetectorCCAL::CENTRAL_ROW = 8; +//int GlueXSensitiveDetectorCCAL::CENTRAL_COLUMN = 8; double GlueXSensitiveDetectorCCAL::WIDTH_OF_BLOCK = 2.0*cm; -double GlueXSensitiveDetectorCCAL::LENGTH_OF_BLOCK = 18.0*cm; +double GlueXSensitiveDetectorCCAL::LENGTH_OF_BLOCK = 20.0*cm; // Light propagation parameters in Compton calorimeter -double GlueXSensitiveDetectorCCAL::ATTENUATION_LENGTH = 60.*cm; +double GlueXSensitiveDetectorCCAL::ATTENUATION_LENGTH = 200.*cm; double GlueXSensitiveDetectorCCAL::C_EFFECTIVE = 13.*cm/ns; // Minimum hit time difference for two hits on the same block double GlueXSensitiveDetectorCCAL::TWO_HIT_TIME_RESOL = 75.*ns; // Minimum energy deposition for a hit -double GlueXSensitiveDetectorCCAL::THRESH_MEV = 20.; +double GlueXSensitiveDetectorCCAL::THRESH_MEV = 5.; int GlueXSensitiveDetectorCCAL::instanceCount = 0; G4Mutex GlueXSensitiveDetectorCCAL::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorCCAL::fVolumeTable; - GlueXSensitiveDetectorCCAL::GlueXSensitiveDetectorCCAL(const G4String& name) : G4VSensitiveDetector(name), fBlocksMap(0), fPointsMap(0) @@ -80,12 +78,14 @@ GlueXSensitiveDetectorCCAL::GlueXSensitiveDetectorCCAL( : G4VSensitiveDetector(src), fBlocksMap(src.fBlocksMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorCCAL &GlueXSensitiveDetectorCCAL::operator=(const GlueXSensitiveDetectorCCAL &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fBlocksMap = src.fBlocksMap; fPointsMap = src.fPointsMap; @@ -94,12 +94,13 @@ GlueXSensitiveDetectorCCAL &GlueXSensitiveDetectorCCAL::operator=(const GlueXSensitiveDetectorCCAL::~GlueXSensitiveDetectorCCAL() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorCCAL::Initialize(G4HCofThisEvent* hce) { - fBlocksMap = new + fBlocksMap = new GlueXHitsMapCCALblock(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapCCALpoint(SensitiveDetectorName, collectionName[1]); @@ -109,7 +110,7 @@ void GlueXSensitiveDetectorCCAL::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorCCAL::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -149,23 +150,23 @@ G4bool GlueXSensitiveDetectorCCAL::ProcessHits(G4Step* step, if (trackinfo->GetGlueXHistory() == 0 && xin.dot(pin) > 0 && Ein/MeV > THRESH_MEV) { - GlueXHitCCALpoint* newPoint = new GlueXHitCCALpoint(); - G4int key = fPointsMap->entries(); - fPointsMap->add(key, newPoint); int pdgtype = track->GetDynamicParticle()->GetPDGcode(); int g3type = GlueXPrimaryGeneratorAction::ConvertPdgToGeant3(pdgtype); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->x_cm = xin[0]/cm; - newPoint->y_cm = xin[1]/cm; - newPoint->z_cm = xin[2]/cm; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; + GlueXHitCCALpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.x_cm = xin[0]/cm; + newPoint.y_cm = xin[1]/cm; + newPoint.z_cm = xin[2]/cm; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; + G4int key = fPointsMap->entries(); + fPointsMap->add(key, newPoint); trackinfo->SetGlueXHistory(4); } @@ -177,8 +178,9 @@ G4bool GlueXSensitiveDetectorCCAL::ProcessHits(G4Step* step, int key = GlueXHitCCALblock::GetKey(column, row); GlueXHitCCALblock *block = (*fBlocksMap)[key]; if (block == 0) { - block = new GlueXHitCCALblock(column, row); - fBlocksMap->add(key, block); + GlueXHitCCALblock newblock(column, row); + fBlocksMap->add(key, newblock); + block = (*fBlocksMap)[key]; } double dist = 0.5 * LENGTH_OF_BLOCK - xlocal[2]; double dEcorr = dEsum * exp(-dist / ATTENUATION_LENGTH); @@ -308,7 +310,7 @@ void GlueXSensitiveDetectorCCAL::EndOfEvent(G4HCofThisEvent*) } int GlueXSensitiveDetectorCCAL::GetIdent(std::string div, - const G4VTouchable *touch) + const G4VTouchable *touch) { const HddsG4Builder* bldr = GlueXDetectorConstruction::GetBuilder(); std::map >::const_iterator iter; @@ -324,10 +326,9 @@ int GlueXSensitiveDetectorCCAL::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorCCAL.hh b/src/GlueXSensitiveDetectorCCAL.hh index 396bbba..e5eefb9 100644 --- a/src/GlueXSensitiveDetectorCCAL.hh +++ b/src/GlueXSensitiveDetectorCCAL.hh @@ -29,7 +29,7 @@ class GlueXSensitiveDetectorCCAL : public G4VSensitiveDetector virtual ~GlueXSensitiveDetectorCCAL(); virtual void Initialize(G4HCofThisEvent* hitCollection); - virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* unused); + virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* ROhist); virtual void EndOfEvent(G4HCofThisEvent* hitCollection); int GetIdent(std::string div, const G4VTouchable *touch); @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorCCAL : public G4VSensitiveDetector GlueXHitsMapCCALblock* fBlocksMap; GlueXHitsMapCCALpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static int CENTRAL_COLUMN; diff --git a/src/GlueXSensitiveDetectorCDC.cc b/src/GlueXSensitiveDetectorCDC.cc index 504062b..dfd22db 100644 --- a/src/GlueXSensitiveDetectorCDC.cc +++ b/src/GlueXSensitiveDetectorCDC.cc @@ -71,8 +71,6 @@ double GlueXSensitiveDetectorCDC::fBscale_par2; G4Mutex GlueXSensitiveDetectorCDC::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorCDC::fVolumeTable; - GlueXSensitiveDetectorCDC::GlueXSensitiveDetectorCDC(const G4String& name) : G4VSensitiveDetector(name), fStrawsMap(0), fPointsMap(0) @@ -117,10 +115,14 @@ GlueXSensitiveDetectorCDC::GlueXSensitiveDetectorCDC(const G4String& name) fDrift_distance[k] = 0.01 * k; // 100 micron increments; fDrift_time[k] = values[k]["t"] * 1000; // from us to ns } - std::map cdc_drift_parms; - jcalib->Get("CDC/cdc_drift_parms", cdc_drift_parms); - fBscale_par1 = cdc_drift_parms.at("bscale_par1"); - fBscale_par2 = cdc_drift_parms.at("bscale_par2"); + + // The /CDC/drift_parameters consists of 2 rows and 10 columns + // The B-field scale parameters B1 and B2 are in columns 9 and 10 + // They should be the same for both rows, so we get them from the first + std::vector< std::vector > cdc_drift_parms; + jcalib->Get("/CDC/drift_parameters", cdc_drift_parms); + fBscale_par1 = cdc_drift_parms.at(0).at(9); + fBscale_par2 = cdc_drift_parms.at(0).at(10); } else { int nvalues = CDC_DRIFT_TABLE_LEN; @@ -130,7 +132,7 @@ GlueXSensitiveDetectorCDC::GlueXSensitiveDetectorCDC(const G4String& name) fDrift_distance[k] = 0.01 * k; // 100 micron increments; fDrift_time[k] = values[k]["t"] * 1000; // from us to ns } - fBscale_par1 = 0; + fBscale_par1 = 1.; fBscale_par2 = 0; } G4cout << "CDC: ALL parameters loaded from ccdb" << G4endl; @@ -151,12 +153,14 @@ GlueXSensitiveDetectorCDC::GlueXSensitiveDetectorCDC( : G4VSensitiveDetector(src), fStrawsMap(src.fStrawsMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorCDC &GlueXSensitiveDetectorCDC::operator=(const GlueXSensitiveDetectorCDC &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fStrawsMap = src.fStrawsMap; fPointsMap = src.fPointsMap; @@ -165,12 +169,13 @@ GlueXSensitiveDetectorCDC &GlueXSensitiveDetectorCDC::operator=(const GlueXSensitiveDetectorCDC::~GlueXSensitiveDetectorCDC() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorCDC::Initialize(G4HCofThisEvent* hce) { - fStrawsMap = new + fStrawsMap = new GlueXHitsMapCDCstraw(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapCDCpoint(SensitiveDetectorName, collectionName[1]); @@ -180,7 +185,7 @@ void GlueXSensitiveDetectorCDC::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorCDC::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -299,23 +304,23 @@ G4bool GlueXSensitiveDetectorCDC::ProcessHits(G4Step* step, if (lastPoint == 0 || lastPoint->track_ != trackID || lastPoint->ring_ != ring) { - GlueXHitCDCpoint* newPoint = new GlueXHitCDCpoint(); + GlueXHitCDCpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.z_cm = x[2]/cm; + newPoint.r_cm = x.perp()/cm; + newPoint.phi_rad = x.phi(); + newPoint.dradius_cm = dradius/cm; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.dEdx_GeV_cm = dEdx/(GeV/cm); + newPoint.sector_ = sector; + newPoint.ring_ = ring; fPointsMap->add(key, newPoint); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->z_cm = x[2]/cm; - newPoint->r_cm = x.perp()/cm; - newPoint->phi_rad = x.phi(); - newPoint->dradius_cm = dradius/cm; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->dEdx_GeV_cm = dEdx/(GeV/cm); - newPoint->sector_ = sector; - newPoint->ring_ = ring; } } @@ -325,8 +330,9 @@ G4bool GlueXSensitiveDetectorCDC::ProcessHits(G4Step* step, int key = GlueXHitCDCstraw::GetKey(ring, sector); GlueXHitCDCstraw *straw = (*fStrawsMap)[key]; if (straw == 0) { - straw = new GlueXHitCDCstraw(ring, sector); - fStrawsMap->add(key, straw); + GlueXHitCDCstraw newstraw(ring, sector); + fStrawsMap->add(key, newstraw); + straw = (*fStrawsMap)[key]; } // Add the hit to the hits vector, maintaining track time ordering, @@ -418,7 +424,7 @@ void GlueXSensitiveDetectorCDC::EndOfEvent(G4HCofThisEvent*) hitview.addCentralDCs(); hddm_s::CentralDC ¢ralDC = hitview.getCentralDC(); - // Collect and output the strawTruthHits + // Collect and output the cdcTruthHits for (siter = straws->begin(); siter != straws->end(); ++siter) { @@ -558,7 +564,7 @@ void GlueXSensitiveDetectorCDC::EndOfEvent(G4HCofThisEvent*) } } - // Collect and output the strawTruthPoints + // Collect and output the cdcTruthPoints for (piter = points->begin(); piter != points->end(); ++piter) { hddm_s::CdcTruthPointList point = centralDC.addCdcTruthPoints(1); point(0).setDEdx(piter->second->dEdx_GeV_cm); @@ -803,10 +809,9 @@ int GlueXSensitiveDetectorCDC::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorCDC.hh b/src/GlueXSensitiveDetectorCDC.hh index cf3180d..f1ebbd4 100644 --- a/src/GlueXSensitiveDetectorCDC.hh +++ b/src/GlueXSensitiveDetectorCDC.hh @@ -31,7 +31,7 @@ class GlueXSensitiveDetectorCDC : public G4VSensitiveDetector virtual ~GlueXSensitiveDetectorCDC(); virtual void Initialize(G4HCofThisEvent* hitCollection); - virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* unused); + virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* ROhist); virtual void EndOfEvent(G4HCofThisEvent* hitCollection); int GetIdent(std::string div, const G4VTouchable *touch); @@ -47,7 +47,7 @@ class GlueXSensitiveDetectorCDC : public G4VSensitiveDetector GlueXHitsMapCDCstraw* fStrawsMap; GlueXHitsMapCDCpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static const double ELECTRON_CHARGE; static double DRIFT_SPEED; diff --git a/src/GlueXSensitiveDetectorCERE.cc b/src/GlueXSensitiveDetectorCERE.cc index 215f2fe..1c01504 100644 --- a/src/GlueXSensitiveDetectorCERE.cc +++ b/src/GlueXSensitiveDetectorCERE.cc @@ -35,8 +35,6 @@ double GlueXSensitiveDetectorCERE::THRESH_PE = 2.; int GlueXSensitiveDetectorCERE::instanceCount = 0; G4Mutex GlueXSensitiveDetectorCERE::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorCERE::fVolumeTable; - GlueXSensitiveDetectorCERE::GlueXSensitiveDetectorCERE(const G4String& name) : G4VSensitiveDetector(name), fTubeHitsMap(0), fPointsMap(0) @@ -73,12 +71,14 @@ GlueXSensitiveDetectorCERE::GlueXSensitiveDetectorCERE( : G4VSensitiveDetector(src), fTubeHitsMap(src.fTubeHitsMap), fPointsMap(src.fPointsMap) { + G4AutoLock tuberier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorCERE &GlueXSensitiveDetectorCERE::operator=(const GlueXSensitiveDetectorCERE &src) { + G4AutoLock tuberier(&fMutex); *(G4VSensitiveDetector*)this = src; fTubeHitsMap = src.fTubeHitsMap; fPointsMap = src.fPointsMap; @@ -87,12 +87,13 @@ GlueXSensitiveDetectorCERE &GlueXSensitiveDetectorCERE::operator=(const GlueXSensitiveDetectorCERE::~GlueXSensitiveDetectorCERE() { + G4AutoLock tuberier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorCERE::Initialize(G4HCofThisEvent* hce) { - fTubeHitsMap = new + fTubeHitsMap = new GlueXHitsMapCEREtube(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapCEREpoint(SensitiveDetectorName, collectionName[1]); @@ -102,7 +103,7 @@ void GlueXSensitiveDetectorCERE::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorCERE::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -152,20 +153,20 @@ G4bool GlueXSensitiveDetectorCERE::ProcessHits(G4Step* step, fabs(lastPoint->y_cm - x[1]/cm) > 2. || fabs(lastPoint->z_cm - x[2]/cm) > 2.) { - GlueXHitCEREpoint* newPoint = new GlueXHitCEREpoint(); + GlueXHitCEREpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.x_cm = x[0]/cm; + newPoint.y_cm = x[1]/cm; + newPoint.z_cm = x[2]/cm; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; fPointsMap->add(key, newPoint); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->x_cm = x[0]/cm; - newPoint->y_cm = x[1]/cm; - newPoint->z_cm = x[2]/cm; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; } } // This sensitive detector is unique in that different volumes are used @@ -181,8 +182,9 @@ G4bool GlueXSensitiveDetectorCERE::ProcessHits(G4Step* step, int key = GlueXHitCEREtube::GetKey(sector); GlueXHitCEREtube *counter = (*fTubeHitsMap)[key]; if (counter == 0) { - counter = new GlueXHitCEREtube(sector); - fTubeHitsMap->add(key, counter); + GlueXHitCEREtube newcounter(sector); + fTubeHitsMap->add(key, newcounter); + counter = (*fTubeHitsMap)[key]; } // Add the hit to the hits vector, maintaining strict time ordering @@ -308,7 +310,7 @@ void GlueXSensitiveDetectorCERE::EndOfEvent(G4HCofThisEvent*) } int GlueXSensitiveDetectorCERE::GetIdent(std::string div, - const G4VTouchable *touch) + const G4VTouchable *touch) { const HddsG4Builder* bldr = GlueXDetectorConstruction::GetBuilder(); std::map >::const_iterator iter; @@ -324,10 +326,9 @@ int GlueXSensitiveDetectorCERE::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorCERE.hh b/src/GlueXSensitiveDetectorCERE.hh index da9e165..3cf652d 100644 --- a/src/GlueXSensitiveDetectorCERE.hh +++ b/src/GlueXSensitiveDetectorCERE.hh @@ -29,7 +29,7 @@ class GlueXSensitiveDetectorCERE : public G4VSensitiveDetector virtual ~GlueXSensitiveDetectorCERE(); virtual void Initialize(G4HCofThisEvent* hitCollection); - virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* unused); + virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* ROhist); virtual void EndOfEvent(G4HCofThisEvent* hitCollection); int GetIdent(std::string div, const G4VTouchable *touch); @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorCERE : public G4VSensitiveDetector GlueXHitsMapCEREtube* fTubeHitsMap; GlueXHitsMapCEREpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static double TWO_HIT_TIME_RESOL; diff --git a/src/GlueXSensitiveDetectorDIRC.cc b/src/GlueXSensitiveDetectorDIRC.cc index 06afade..c47ed9a 100644 --- a/src/GlueXSensitiveDetectorDIRC.cc +++ b/src/GlueXSensitiveDetectorDIRC.cc @@ -9,6 +9,7 @@ #include "GlueXPrimaryGeneratorAction.hh" #include "GlueXUserEventInformation.hh" #include "GlueXUserTrackInformation.hh" +#include "GlueXUserOptions.hh" #include "G4VPhysicalVolume.hh" #include "G4PVPlacement.hh" @@ -17,6 +18,8 @@ #include "G4Step.hh" #include "G4SDManager.hh" #include "G4ios.hh" +#include "G4TransportationManager.hh" +#include "G4ParallelWorldProcess.hh" #include @@ -24,7 +27,8 @@ #define OPTICAL_PHOTON 50 // Cutoff on the total number of allowed hits -int GlueXSensitiveDetectorDIRC::MAX_HITS = 500; +int GlueXSensitiveDetectorDIRC::MAX_HITS = 1000; +int GlueXSensitiveDetectorDIRC::MAX_PIXELS = 6912; // Minimum hit time difference for two hits on the same tube double GlueXSensitiveDetectorDIRC::TWO_HIT_TIME_RESOL = 50*ns; @@ -32,7 +36,7 @@ double GlueXSensitiveDetectorDIRC::TWO_HIT_TIME_RESOL = 50*ns; int GlueXSensitiveDetectorDIRC::instanceCount = 0; G4Mutex GlueXSensitiveDetectorDIRC::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorDIRC::fVolumeTable; +TGraph *GlueXSensitiveDetectorDIRC::fDetEff = 0; GlueXSensitiveDetectorDIRC::GlueXSensitiveDetectorDIRC(const G4String& name) : G4VSensitiveDetector(name) @@ -43,14 +47,14 @@ GlueXSensitiveDetectorDIRC::GlueXSensitiveDetectorDIRC(const G4String& name) // the drift-time properties of hits in the DIRC, you must delete all old // objects of this class and create new ones. - G4AutoLock tuberier(&fMutex); + G4AutoLock barrier(&fMutex); if (instanceCount++ == 0) { extern int run_number; extern jana::JApplication *japp; if (japp == 0) { G4cerr << "Error in GlueXSensitiveDetector constructor - " - << "jana global DApplication object not set, " - << "cannot continue." << G4endl; + << "jana global DApplication object not set, " + << "cannot continue." << G4endl; exit(-1); } jana::JCalibration *jcalib = japp->GetJCalibration(run_number); @@ -59,23 +63,43 @@ GlueXSensitiveDetectorDIRC::GlueXSensitiveDetectorDIRC(const G4String& name) G4cout << "DIRC: ALL parameters loaded from ccdb" << G4endl; } } + + GlueXUserOptions *user_opts = GlueXUserOptions::GetInstance(); + std::map dirclutpars; + if (user_opts->Find("DIRCLUT", dirclutpars)) { + fLutId = dirclutpars[1]; + } + else { + fLutId = 100; + } + std::map dircledpars; + if (user_opts->Find("DIRCLED", dircledpars)){ + fLED = true; + } + else { + fLED = false; + } + } GlueXSensitiveDetectorDIRC::GlueXSensitiveDetectorDIRC(const GlueXSensitiveDetectorDIRC &src) : G4VSensitiveDetector(src) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorDIRC &GlueXSensitiveDetectorDIRC::operator=(const - GlueXSensitiveDetectorDIRC &src) + GlueXSensitiveDetectorDIRC &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; return *this; } GlueXSensitiveDetectorDIRC::~GlueXSensitiveDetectorDIRC() { + G4AutoLock barrier(&fMutex); --instanceCount; } @@ -84,7 +108,7 @@ void GlueXSensitiveDetectorDIRC::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorDIRC::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { const G4ThreeVector &pin = step->GetPreStepPoint()->GetMomentum(); @@ -114,13 +138,15 @@ G4bool GlueXSensitiveDetectorDIRC::ProcessHits(G4Step* step, // order of appearance in the event simulation. G4Track *track = step->GetTrack(); - // G4int trackID = track->GetTrackID(); GlueXUserTrackInformation *trackinfo = (GlueXUserTrackInformation*) track->GetUserInformation(); int itrack = trackinfo->GetGlueXTrackID(); + G4String volname = touch->GetVolume()->GetName(); + + // radiator volume: BNNM (NN = bar number 0-47 and M is sub-bar character A-D) + int ibar = 10*((int)volname(1,1)(0)-48)+(int)volname(2,1)(0)-48; // this is nasty, but it works + if (volname(0,1)(0) == 'B' && ibar >= 0 && ibar < 48) { - // radiator volume - if (touch->GetVolume()->GetName() == "QZBL") { if (trackinfo->GetGlueXHistory() == 0 && itrack > 0 && xin.dot(pin) > 0) { int pdgtype = track->GetDynamicParticle()->GetPDGcode(); int g3type = GlueXPrimaryGeneratorAction::ConvertPdgToGeant3(pdgtype); @@ -135,31 +161,160 @@ G4bool GlueXSensitiveDetectorDIRC::ProcessHits(G4Step* step, barhit.py_GeV = pin[1]/GeV; barhit.pz_GeV = pin[2]/GeV; barhit.pdg = g3type; - barhit.bar = touch_hist->GetReplicaNumber(0)/4; // each bar is glued from 4 pieces - barhit.track = itrack; + barhit.bar = ibar; // from HDDS geometry + barhit.track = itrack; // track id of the charged particle fHitsBar.push_back(barhit); } return true; } + // wedge and mirrors volumes + + if (volname == "WM1N" || volname == "WM2N" || volname == "WM1S" || volname == "WM2S" || + volname == "FTMN" || volname == "FTMS" || + volname == "TM1N" || volname == "TM2N" || volname == "TM3N" || + volname == "TM1S" || volname == "TM2S" || volname == "TM3S" || + volname == "SM1N" || volname == "SM2N" || volname == "SM1S" || volname == "SM2S" || + volname == "OWDG" || + (volname(0,1)(0) == 'A' && volname(0,1)(1) == 'G') ) + { + + GlueXHitDIRCWob wobhit; + wobhit.track = track->GetTrackID(); + + // store normal to the closest boundary + G4int hNavId = G4ParallelWorldProcess::GetHypNavigatorID(); + std::vector::iterator iNav = + G4TransportationManager::GetTransportationManager()->GetActiveNavigatorsIterator(); + + G4bool valid; + G4ThreeVector localNormal = (iNav[hNavId])->GetLocalExitNormal(&valid); + if (valid){ + int mid=-1; + if (volname == "OWDG") { + if (localNormal.y()<-0.999) + mid=1; + else if (localNormal.y()>0.999) + mid=2; + else if(localNormal.z()>0.999) + mid=3; + else if(fabs(localNormal.z()+0.86)<0.01) + mid=4; + } + if (volname == "SM1N" || volname == "SM1S") + mid = 5; + if (volname == "SM2N" || volname == "SM2S") + mid = 6; + if (volname == "WM1N" || volname == "WM1S") + mid = 7; + if (volname == "WM2N" || volname == "WM2S") + mid = 8; + if (volname == "FTMN" || volname == "FTMS") + mid = 0; + if (volname == "TM1N" || volname == "TM1S") + mid=91; + if (volname == "TM2N" || volname == "TM2S") + mid=92; + if (volname == "TM3N" || volname == "TM3S") + mid=93; + if ((volname(0,1)(0) == 'A' && volname(0,1)(1) == 'G')) + mid=100; + + if (mid!=-1) { + G4double normalId = mid;// localNormal.x() + 10*localNormal.y() + 100*localNormal.z(); + wobhit.normalId = normalId; + fHitsWob.push_back(wobhit); + } + } + return true; + } + // PMT's pixel volume - if (touch->GetVolume()->GetName() == "PIXV"){ - if ((int)fHitsPmt.size() < MAX_HITS){ + if (volname == "PIXV") { + if ((int)fHitsPmt.size() < MAX_HITS) { + + // fix propagation speed for op + double tracklen=track->GetTrackLength()/cm; + double en=Ein/GeV; + double refindex= 1.43603+0.0132404*en-0.00225287*en*en+0.000500109*en*en*en; + double time_fixed=tracklen/(29.9792458/refindex); + +#ifdef DIRC_CHECK_PROPAGATION_TIME + double l_QZBL = 9.1 + 0.96 + 122.5; // 2 * (4*122.5) // 2 * bar length + wedge + window + double l_EPOTEK = 0.005 + 8 * 0.005; // window+wedge glue + 6 * bar joing glue + double l_AIR = 2 * 0.01; // air gap to mirror + double l_H2O = tracklen - l_QZBL - l_EPOTEK - l_AIR; + + // hard coded propagation time for 3.5 eV OpticalPhoton + double angle = 45/180*3.14159; + double time_propagated = l_QZBL/(29.9792458/1.476)/cos(angle); + time_propagated += l_EPOTEK/(29.9792458/1.616)/cos(angle); + time_propagated += l_AIR/(29.9792458)/cos(angle); + time_propagated += l_H2O/(29.9792458/1.343); + G4cout<<"Propagated time = "< 1) { G4cout << G4endl - << "--------> Hits Collection: in this event there are " - << fHitsBar.size() << " bar hits:" - << G4endl; + << "--------> Hits Collection: in this event there are " + << fHitsBar.size() << " bar hits:" + << G4endl; for(unsigned int h=0; h Hits Collection: in this event there are " - << fHitsPmt.size() << " PMT hits: " - << G4endl; + << "--------> Hits Collection: in this event there are " + << fHitsPmt.size() << " PMT hits: " + << G4endl; for(unsigned int h=0; hgetOutputRecord(); if (record == 0) { G4cerr << "GlueXSensitiveDetectorDIRC::EndOfEvent error - " - << "hits seen but no output hddm record to save them into, " - << "cannot continue!" << G4endl; + << "hits seen but no output hddm record to save them into, " + << "cannot continue!" << G4endl; exit(1); } @@ -223,7 +384,7 @@ void GlueXSensitiveDetectorDIRC::EndOfEvent(G4HCofThisEvent*) bhit(0).setTrack(fHitsBar[h].track); } - // Collect and output the DircTruthPoints + // Collect and output the DircTruthPmtHit for(unsigned int h=0; hfind(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; } + +double GlueXSensitiveDetectorDIRC::GetDetectionEfficiency(double energy) +{ + if (fDetEff == 0) + InitializeDetEff(); + double wavelength = CLHEP::hbarc * CLHEP::twopi / energy; + return fDetEff->Eval(wavelength / nm); +} + +void GlueXSensitiveDetectorDIRC::InitializeDetEff() +{ + G4AutoLock barrier(&fMutex); + // quantum efficiency for H12700 + // defined for wavelength in the range [0, 1000] nm + double fEfficiency[1000] = {0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.196823, 0.202016, 0.206993, 0.211762, 0.216329, + 0.220700, 0.224884, 0.228885, 0.232711, 0.236366, + 0.239858, 0.243192, 0.246373, 0.249408, 0.252301, + 0.255058, 0.257683, 0.260182, 0.262560, 0.264822, + 0.266971, 0.269013, 0.270951, 0.272791, 0.274535, + 0.276189, 0.277756, 0.279239, 0.280643, 0.281971, + 0.283227, 0.284413, 0.285534, 0.286592, 0.287590, + 0.288531, 0.289419, 0.290255, 0.291043, 0.291785, + 0.292484, 0.293142, 0.293762, 0.294345, 0.294894, + 0.295412, 0.295899, 0.296358, 0.296791, 0.297200, + 0.297585, 0.297950, 0.298296, 0.298624, 0.298935, + 0.299231, 0.299514, 0.299784, 0.300043, 0.300291, + 0.300531, 0.300763, 0.300988, 0.301206, 0.301420, + 0.301629, 0.301835, 0.302038, 0.302238, 0.302437, + 0.302636, 0.302833, 0.303031, 0.303230, 0.303429, + 0.303630, 0.303832, 0.304037, 0.304244, 0.304453, + 0.304666, 0.304881, 0.305099, 0.305321, 0.305545, + 0.305774, 0.306005, 0.306240, 0.306478, 0.306720, + 0.306964, 0.307212, 0.307463, 0.307717, 0.307973, + 0.308232, 0.308493, 0.308756, 0.309022, 0.309288, + 0.309557, 0.309826, 0.310096, 0.310367, 0.310637, + 0.310908, 0.311178, 0.311447, 0.311715, 0.311981, + 0.312245, 0.312507, 0.312766, 0.313022, 0.313274, + 0.313522, 0.313766, 0.314005, 0.314238, 0.314466, + 0.314688, 0.314903, 0.315111, 0.315311, 0.315504, + 0.315688, 0.315863, 0.316029, 0.316185, 0.316331, + 0.316466, 0.316590, 0.316703, 0.316804, 0.316893, + 0.316968, 0.317031, 0.317080, 0.317114, 0.317135, + 0.317140, 0.317130, 0.317105, 0.317063, 0.317005, + 0.316931, 0.316839, 0.316729, 0.316602, 0.316457, + 0.316292, 0.316109, 0.315907, 0.315686, 0.315444, + 0.315182, 0.314900, 0.314598, 0.314274, 0.313929, + 0.313563, 0.313175, 0.312765, 0.312333, 0.311878, + 0.311402, 0.310902, 0.310379, 0.309834, 0.309265, + 0.308673, 0.308057, 0.307418, 0.306755, 0.306068, + 0.305357, 0.304622, 0.303863, 0.303080, 0.302273, + 0.301442, 0.300586, 0.299706, 0.298802, 0.297874, + 0.296921, 0.295944, 0.294943, 0.293918, 0.292869, + 0.291796, 0.290699, 0.289579, 0.288434, 0.287266, + 0.286075, 0.284860, 0.283623, 0.282362, 0.281078, + 0.279772, 0.278443, 0.277093, 0.275720, 0.274325, + 0.272908, 0.271470, 0.270012, 0.268532, 0.267031, + 0.265510, 0.263970, 0.262409, 0.260829, 0.259229, + 0.257611, 0.255974, 0.254319, 0.252646, 0.250956, + 0.249248, 0.247524, 0.245782, 0.244025, 0.242252, + 0.240464, 0.238661, 0.236843, 0.235011, 0.233165, + 0.231306, 0.229433, 0.227549, 0.225652, 0.223743, + 0.221823, 0.219892, 0.217951, 0.216000, 0.214040, + 0.212070, 0.210092, 0.208105, 0.206111, 0.204110, + 0.202102, 0.200087, 0.198067, 0.196041, 0.194011, + 0.191976, 0.189937, 0.187894, 0.185849, 0.183801, + 0.181750, 0.179699, 0.177646, 0.175592, 0.173538, + 0.171484, 0.169431, 0.167380, 0.165330, 0.163282, + 0.161236, 0.159194, 0.157155, 0.155120, 0.153089, + 0.151063, 0.149042, 0.147027, 0.145018, 0.143016, + 0.141020, 0.139032, 0.137052, 0.135080, 0.133116, + 0.131162, 0.129217, 0.127281, 0.125356, 0.123442, + 0.121538, 0.119645, 0.117765, 0.115896, 0.114039, + 0.112195, 0.110364, 0.108547, 0.106743, 0.104953, + 0.103177, 0.101415, 0.099669, 0.097937, 0.096221, + 0.094521, 0.092836, 0.091168, 0.089515, 0.087880, + 0.086261, 0.084659, 0.083074, 0.081506, 0.079956, + 0.078424, 0.076910, 0.075413, 0.073935, 0.072475, + 0.071034, 0.069611, 0.068206, 0.066821, 0.065454, + 0.064106, 0.062776, 0.061466, 0.060175, 0.058903, + 0.057650, 0.056416, 0.055201, 0.054005, 0.052829, + 0.051671, 0.050532, 0.049413, 0.048312, 0.047230, + 0.046166, 0.045122, 0.044096, 0.043088, 0.042099, + 0.041128, 0.040175, 0.039241, 0.038324, 0.037424, + 0.036542, 0.035678, 0.034831, 0.034000, 0.033187, + 0.032389, 0.031609, 0.030844, 0.030096, 0.029363, + 0.028645, 0.027943, 0.027255, 0.026583, 0.025924, + 0.025280, 0.024650, 0.024033, 0.023430, 0.022840, + 0.022262, 0.021697, 0.021144, 0.020603, 0.020073, + 0.019555, 0.019048, 0.018551, 0.018065, 0.017588, + 0.017122, 0.016665, 0.016217, 0.015777, 0.015346, + 0.014924, 0.014509, 0.014102, 0.013702, 0.013310, + 0.012924, 0.012544, 0.012171, 0.011803, 0.011442, + 0.011085, 0.010734, 0.010388, 0.010047, 0.009710, + 0.009377, 0.009048, 0.008724, 0.008403, 0.008085, + 0.007772, 0.007461, 0.007154, 0.006850, 0.006548, + 0.006250, 0.005955, 0.005663, 0.005374, 0.005087, + 0.004804, 0.004523, 0.004246, 0.003972, 0.003701, + 0.003434, 0.003171, 0.002911, 0.002656, 0.002405, + 0.002159, 0.001918, 0.001682, 0.001453, 0.001229, + 0.001013, 0.000803, 0.000602, 0.000409, 0.000225, + 0.000051, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 0.000000, 0.000000 + }; + double fLambda[1000]; + for (Int_t i=0; i < 1000; i++) { + fLambda[i] = i; + } + fDetEff = new TGraph(1000, fLambda, fEfficiency); +} diff --git a/src/GlueXSensitiveDetectorDIRC.hh b/src/GlueXSensitiveDetectorDIRC.hh index 4b23206..e1c83bc 100644 --- a/src/GlueXSensitiveDetectorDIRC.hh +++ b/src/GlueXSensitiveDetectorDIRC.hh @@ -17,9 +17,11 @@ #include "G4AutoLock.hh" #include "GlueXHitDIRCflash.hh" -#include "GlueXHitDIRCpoint.hh" #include "GlueXHitDIRCPmt.hh" #include "GlueXHitDIRCBar.hh" +#include "GlueXHitDIRCWob.hh" + +#include class G4Step; class G4HCofThisEvent; @@ -33,23 +35,32 @@ class GlueXSensitiveDetectorDIRC : public G4VSensitiveDetector virtual ~GlueXSensitiveDetectorDIRC(); virtual void Initialize(G4HCofThisEvent* hitCollection); - virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* unused); + virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* ROhist); virtual void EndOfEvent(G4HCofThisEvent* hitCollection); int GetIdent(std::string div, const G4VTouchable *touch); + static double GetDetectionEfficiency(double energy_GeV); + private: std::vector fHitsBar; + std::vector fHitsWob; std::vector fHitsPmt; + int fLutId; + bool fLED; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; + static int MAX_PIXELS; // put all other detector response parameters here static double TWO_HIT_TIME_RESOL; static int instanceCount; static G4Mutex fMutex; + + static TGraph *fDetEff; + static void InitializeDetEff(); }; #endif diff --git a/src/GlueXSensitiveDetectorFCAL.cc b/src/GlueXSensitiveDetectorFCAL.cc index 387610c..91f2767 100644 --- a/src/GlueXSensitiveDetectorFCAL.cc +++ b/src/GlueXSensitiveDetectorFCAL.cc @@ -43,8 +43,6 @@ double GlueXSensitiveDetectorFCAL::THRESH_MEV = 5.; int GlueXSensitiveDetectorFCAL::instanceCount = 0; G4Mutex GlueXSensitiveDetectorFCAL::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorFCAL::fVolumeTable; - GlueXSensitiveDetectorFCAL::GlueXSensitiveDetectorFCAL(const G4String& name) : G4VSensitiveDetector(name), fBlocksMap(0), fPointsMap(0) @@ -91,12 +89,14 @@ GlueXSensitiveDetectorFCAL::GlueXSensitiveDetectorFCAL( : G4VSensitiveDetector(src), fBlocksMap(src.fBlocksMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorFCAL &GlueXSensitiveDetectorFCAL::operator=(const GlueXSensitiveDetectorFCAL &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fBlocksMap = src.fBlocksMap; fPointsMap = src.fPointsMap; @@ -105,12 +105,13 @@ GlueXSensitiveDetectorFCAL &GlueXSensitiveDetectorFCAL::operator=(const GlueXSensitiveDetectorFCAL::~GlueXSensitiveDetectorFCAL() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorFCAL::Initialize(G4HCofThisEvent* hce) { - fBlocksMap = new + fBlocksMap = new GlueXHitsMapFCALblock(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapFCALpoint(SensitiveDetectorName, collectionName[1]); @@ -120,7 +121,7 @@ void GlueXSensitiveDetectorFCAL::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorFCAL::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); const G4ThreeVector &pin = step->GetPreStepPoint()->GetMomentum(); @@ -157,23 +158,23 @@ G4bool GlueXSensitiveDetectorFCAL::ProcessHits(G4Step* step, if (trackinfo->GetGlueXHistory() == 0 && xin.dot(pin) > 0 && Ein/MeV > THRESH_MEV) { - GlueXHitFCALpoint* newPoint = new GlueXHitFCALpoint(); - G4int key = fPointsMap->entries(); - fPointsMap->add(key, newPoint); int pdgtype = track->GetDynamicParticle()->GetPDGcode(); int g3type = GlueXPrimaryGeneratorAction::ConvertPdgToGeant3(pdgtype); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->x_cm = xin[0]/cm; - newPoint->y_cm = xin[1]/cm; - newPoint->z_cm = xin[2]/cm; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; + GlueXHitFCALpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.x_cm = xin[0]/cm; + newPoint.y_cm = xin[1]/cm; + newPoint.z_cm = xin[2]/cm; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; + G4int key = fPointsMap->entries(); + fPointsMap->add(key, newPoint); trackinfo->SetGlueXHistory(2); } @@ -185,43 +186,101 @@ G4bool GlueXSensitiveDetectorFCAL::ProcessHits(G4Step* step, int key = GlueXHitFCALblock::GetKey(column, row); GlueXHitFCALblock *block = (*fBlocksMap)[key]; if (block == 0) { - block = new GlueXHitFCALblock(column, row); - fBlocksMap->add(key, block); + GlueXHitFCALblock newblock(column, row); + fBlocksMap->add(key, newblock); + block = (*fBlocksMap)[key]; } - double dist = 0.5 * LENGTH_OF_BLOCK - xlocal[2]; - double dEcorr = dEsum * exp(-dist / ATTENUATION_LENGTH); - double tcorr = t + dist / C_EFFECTIVE; - - // Add the hit to the hits vector, maintaining strict time ordering - - int merge_hit = 0; - std::vector::iterator hiter; - for (hiter = block->hits.begin(); hiter != block->hits.end(); ++hiter) { - if (fabs(hiter->t_ns*ns - tcorr) < TWO_HIT_TIME_RESOL) { - merge_hit = 1; - break; + + // Handle hits in the lead glass + + if (touch->GetVolume()->GetName() == "LGBL") { + double dist = 0.5 * LENGTH_OF_BLOCK - xlocal[2]; + double dEcorr = dEsum * exp(-dist / ATTENUATION_LENGTH); + double tcorr = t + dist / C_EFFECTIVE; + + // Apply effective response corrections, depending on particle type + int pmass = track->GetDynamicParticle()->GetMass(); + if (pmass < 1 * MeV) { // must be one of e+,e-,gamma + dEcorr *= 0.976; } - else if (hiter->t_ns*ns > tcorr) { - break; + else { + double gamma = Ein / pmass; // nothing massless here + dEcorr *= (gamma > 1.25)? 1.35 : 0; } - } - if (merge_hit) { - // Use the time from the earlier hit but add the energy deposition - hiter->E_GeV += dEcorr/GeV; - if (hiter->t_ns*ns > tcorr) { + + if (dEcorr == 0) + return true; + + // Add the hit to the hits vector, maintaining strict time ordering + + int merge_hit = 0; + std::vector::iterator hiter; + for (hiter = block->hits.begin(); hiter != block->hits.end(); ++hiter) { + if (fabs(hiter->t_ns*ns - tcorr) < TWO_HIT_TIME_RESOL) { + merge_hit = 1; + break; + } + else if (hiter->t_ns*ns > tcorr) { + break; + } + } + if (merge_hit) { + // Merge the time with the existing hit, add the energy deposition + hiter->t_ns = hiter->t_ns * hiter->E_GeV + dEcorr/GeV * tcorr/ns; + hiter->E_GeV += dEcorr/GeV; + hiter->t_ns /= hiter->E_GeV; + } + else if ((int)block->hits.size() < MAX_HITS) { + // create new hit + hiter = block->hits.insert(hiter, GlueXHitFCALblock::hitinfo_t()); + hiter->E_GeV = dEcorr/GeV; hiter->t_ns = tcorr/ns; + hiter->dE_lightguide_GeV = 0; + hiter->t_lightguide_ns = 0; + } + else { + G4cerr << "GlueXSensitiveDetectorFCAL::ProcessHits error: " + << "max hit count " << MAX_HITS << " exceeded, truncating!" + << G4endl; } } - else if ((int)block->hits.size() < MAX_HITS) { - // create new hit - hiter = block->hits.insert(hiter, GlueXHitFCALblock::hitinfo_t()); - hiter->E_GeV = dEcorr/GeV; - hiter->t_ns = tcorr/ns; - } - else { - G4cerr << "GlueXSensitiveDetectorFCAL::ProcessHits error: " - << "max hit count " << MAX_HITS << " exceeded, truncating!" - << G4endl; + + // If not in the lead glass, it should be in the light guide + + else if (touch->GetVolume()->GetName() == "LGLG") { + + // Add the hit to the hits vector, maintaining strict time ordering + + int merge_hit = 0; + std::vector::iterator hiter; + for (hiter = block->hits.begin(); hiter != block->hits.end(); ++hiter) { + if (fabs(hiter->t_ns*ns - t) < TWO_HIT_TIME_RESOL) { + merge_hit = 1; + break; + } + else if (hiter->t_ns*ns > t) { + break; + } + } + if (merge_hit) { + hiter->t_lightguide_ns = + (hiter->t_lightguide_ns * hiter->dE_lightguide_GeV + + t/ns * dEsum/GeV) / (hiter->dE_lightguide_GeV + dEsum/GeV); + hiter->dE_lightguide_GeV += dEsum/GeV; + } + else if ((int)block->hits.size() < MAX_HITS) { + // create new hit + hiter = block->hits.insert(hiter, GlueXHitFCALblock::hitinfo_t()); + hiter->dE_lightguide_GeV = dEsum/GeV; + hiter->t_lightguide_ns = t/ns; + hiter->E_GeV = 0; + hiter->t_ns = t/ns; + } + else { + G4cerr << "GlueXSensitiveDetectorFCAL::ProcessHits error: " + << "max hit count " << MAX_HITS << " exceeded, truncating!" + << G4endl; + } } } return true; @@ -298,6 +357,12 @@ void GlueXSensitiveDetectorFCAL::EndOfEvent(G4HCofThisEvent*) hddm_s::FcalTruthHitList thit = block(0).addFcalTruthHits(1); thit(0).setE(hits[ih].E_GeV); thit(0).setT(hits[ih].t_ns); + if (hits[ih].dE_lightguide_GeV > 0) { + hddm_s::FcalTruthLightGuideList lghit = + thit(0).addFcalTruthLightGuides(1); + lghit(0).setDE(hits[ih].dE_lightguide_GeV); + lghit(0).setT(hits[ih].t_lightguide_ns); + } } } } @@ -322,7 +387,7 @@ void GlueXSensitiveDetectorFCAL::EndOfEvent(G4HCofThisEvent*) } int GlueXSensitiveDetectorFCAL::GetIdent(std::string div, - const G4VTouchable *touch) + const G4VTouchable *touch) { const HddsG4Builder* bldr = GlueXDetectorConstruction::GetBuilder(); std::map >::const_iterator iter; @@ -338,10 +403,9 @@ int GlueXSensitiveDetectorFCAL::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorFCAL.hh b/src/GlueXSensitiveDetectorFCAL.hh index 0df7869..3b03762 100644 --- a/src/GlueXSensitiveDetectorFCAL.hh +++ b/src/GlueXSensitiveDetectorFCAL.hh @@ -29,7 +29,7 @@ class GlueXSensitiveDetectorFCAL : public G4VSensitiveDetector virtual ~GlueXSensitiveDetectorFCAL(); virtual void Initialize(G4HCofThisEvent* hitCollection); - virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* unused); + virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* ROhist); virtual void EndOfEvent(G4HCofThisEvent* hitCollection); int GetIdent(std::string div, const G4VTouchable *touch); @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorFCAL : public G4VSensitiveDetector GlueXHitsMapFCALblock* fBlocksMap; GlueXHitsMapFCALpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static int CENTRAL_COLUMN; diff --git a/src/GlueXSensitiveDetectorFDC.cc b/src/GlueXSensitiveDetectorFDC.cc index e38e0b9..eb83b1a 100644 --- a/src/GlueXSensitiveDetectorFDC.cc +++ b/src/GlueXSensitiveDetectorFDC.cc @@ -64,12 +64,22 @@ double GlueXSensitiveDetectorFDC::ACTIVE_AREA_OUTER_RADIUS = 48.5*cm; double GlueXSensitiveDetectorFDC::ANODE_CATHODE_SPACING = 0.5*cm; double GlueXSensitiveDetectorFDC::WIRE_SPACING = 1.0*cm; double GlueXSensitiveDetectorFDC::STRIP_SPACING = 0.5*cm; -double GlueXSensitiveDetectorFDC::U_OF_WIRE_ZERO = -47.5*cm; //-(WIRES_PER_PLANE-1)*WIRE_SPACING/2 -double GlueXSensitiveDetectorFDC::U_OF_STRIP_ZERO = -47.75*cm; //-(STRIPS_PER_PLANE-1)*STRIP_SPACING/2 +double GlueXSensitiveDetectorFDC::U_OF_WIRE_ONE = -47.5*cm; //-(WIRES_PER_PLANE-1)*WIRE_SPACING/2 +double GlueXSensitiveDetectorFDC::U_OF_STRIP_ONE = -47.75*cm; //-(STRIPS_PER_PLANE-1)*STRIP_SPACING/2 double GlueXSensitiveDetectorFDC::CATHODE_ROT_ANGLE = 1.309; // radians (75 degrees) double GlueXSensitiveDetectorFDC::STRIP_GAP = 0.1*cm; double GlueXSensitiveDetectorFDC::STRIP_NODES = 3; +// Parameters for calculating the drift time-distance relation +double GlueXSensitiveDetectorFDC::LORENTZ_NR_PAR1; +double GlueXSensitiveDetectorFDC::LORENTZ_NR_PAR2; +double GlueXSensitiveDetectorFDC::LORENTZ_NZ_PAR1; +double GlueXSensitiveDetectorFDC::LORENTZ_NZ_PAR2; +double GlueXSensitiveDetectorFDC::DRIFT_RES_PARMS[3]; +double GlueXSensitiveDetectorFDC::DRIFT_FUNC_PARMS[6]; +double GlueXSensitiveDetectorFDC::DRIFT_BSCALE_PAR1; +double GlueXSensitiveDetectorFDC::DRIFT_BSCALE_PAR2; + // Parameters for estimating magnetic field drift effects double GlueXSensitiveDetectorFDC::DIFFUSION_COEFF = 1.1e-6*cm*cm/s; // cm^2/s --> 200 microns at 1 cm double GlueXSensitiveDetectorFDC::K2 = 1.15; @@ -80,12 +90,15 @@ double GlueXSensitiveDetectorFDC::wire_dead_zone_radius[4] = double GlueXSensitiveDetectorFDC::strip_dead_zone_radius[4] = {1.3*cm, 1.3*cm, 1.3*cm, 1.3*cm}; +// Drift time - distance lookup table +int GlueXSensitiveDetectorFDC::drift_table_len; +double *GlueXSensitiveDetectorFDC::drift_table_t_ns; +double *GlueXSensitiveDetectorFDC::drift_table_d_cm; + int GlueXSensitiveDetectorFDC::instanceCount = 0; G4Mutex GlueXSensitiveDetectorFDC::fMutex = G4MUTEX_INITIALIZER; int GlueXSensitiveDetectorFDC::fDrift_clusters = 0; -std::map GlueXSensitiveDetectorFDC::fVolumeTable; - GlueXSensitiveDetectorFDC::GlueXSensitiveDetectorFDC(const G4String& name) : G4VSensitiveDetector(name), fWiresMap(0), fCathodesMap(0), fPointsMap(0) @@ -128,8 +141,72 @@ GlueXSensitiveDetectorFDC::GlueXSensitiveDetectorFDC(const G4String& name) THRESH_KEV = fdc_parms.at("FDC_THRESH_KEV"); THRESH_STRIPS = fdc_parms.at("FDC_THRESH_STRIPS"); DIFFUSION_COEFF = fdc_parms.at("FDC_DIFFUSION_COEFF")*cm*cm/s; - U_OF_WIRE_ZERO = -(WIRES_PER_PLANE -1) * WIRE_SPACING / 2; - U_OF_STRIP_ZERO = -(STRIPS_PER_PLANE -1) * STRIP_SPACING / 2; + U_OF_WIRE_ONE = -(WIRES_PER_PLANE -1) * WIRE_SPACING / 2; + U_OF_STRIP_ONE = -(STRIPS_PER_PLANE -1) * STRIP_SPACING / 2; + + // Parameters for correcting for deflection due to Lorentz force + std::map lorentz_parms; + jcalib->Get("FDC/lorentz_deflection_parms", lorentz_parms); + LORENTZ_NR_PAR1 = lorentz_parms["nr_par1"]; + LORENTZ_NR_PAR2 = lorentz_parms["nr_par2"]; + LORENTZ_NZ_PAR1 = lorentz_parms["nz_par1"]; + LORENTZ_NZ_PAR2 = lorentz_parms["nz_par2"]; + + // Parameters for accounting for variation in drift distance from FDC + std::map drift_res_parms; + jcalib->Get("FDC/drift_resolution_parms", drift_res_parms); + DRIFT_RES_PARMS[0] = drift_res_parms["p0"]; + DRIFT_RES_PARMS[1] = drift_res_parms["p1"]; + DRIFT_RES_PARMS[2] = drift_res_parms["p2"]; + + // Time-to-distance function parameters for FDC + std::map drift_func_parms; + jcalib->Get("FDC/drift_function_parms", drift_func_parms); + DRIFT_FUNC_PARMS[0] = drift_func_parms["p0"]; + DRIFT_FUNC_PARMS[1] = drift_func_parms["p1"]; + DRIFT_FUNC_PARMS[2] = drift_func_parms["p2"]; + DRIFT_FUNC_PARMS[3] = drift_func_parms["p3"]; + DRIFT_FUNC_PARMS[4] = 1000.; + DRIFT_FUNC_PARMS[5] = 0.; + std::map drift_func_ext; + if (jcalib->Get("FDC/drift_function_ext", drift_func_ext) == false) { + DRIFT_FUNC_PARMS[4] = drift_func_ext["p4"]; + DRIFT_FUNC_PARMS[5] = drift_func_ext["p5"]; + } + + // Factors for taking care of B-dependence of drift time for FDC + std::map fdc_drift_parms; + jcalib->Get("FDC/fdc_drift_parms", fdc_drift_parms); + DRIFT_BSCALE_PAR1 = fdc_drift_parms["bscale_par1"]; + DRIFT_BSCALE_PAR2 = fdc_drift_parms["bscale_par2"]; + + // Build a lookup table of drift time->distance for the FDC, + // used in the code to build an efficient reverse-map function. + drift_table_len = 1000; + drift_table_t_ns = new double[drift_table_len]; + drift_table_d_cm = new double[drift_table_len]; + double thigh = DRIFT_FUNC_PARMS[4]; + double tstep = 0.5; //ns + for (int j=0; j < drift_table_len; j++) { + double t = j * tstep; + if (t < thigh) { + double t2 = t*t; + drift_table_t_ns[j] = t; + drift_table_d_cm[j] = DRIFT_FUNC_PARMS[0] * sqrt(t) + + DRIFT_FUNC_PARMS[1] * t + + DRIFT_FUNC_PARMS[2] * t2 + + DRIFT_FUNC_PARMS[3] * t*t2; + } + else { + double thigh2 = thigh * thigh; + drift_table_t_ns[j] = t; + drift_table_d_cm[j] = DRIFT_FUNC_PARMS[0] * sqrt(thigh) + + DRIFT_FUNC_PARMS[1] * thigh + + DRIFT_FUNC_PARMS[2] * thigh2 + + DRIFT_FUNC_PARMS[3] * thigh2 * thigh + + DRIFT_FUNC_PARMS[5] * (t - thigh); + } + } G4cout << "FDC: ALL parameters loaded from ccdb" << G4endl; @@ -151,12 +228,14 @@ GlueXSensitiveDetectorFDC::GlueXSensitiveDetectorFDC( fCathodesMap(src.fCathodesMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorFDC &GlueXSensitiveDetectorFDC::operator=(const GlueXSensitiveDetectorFDC &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fWiresMap = src.fWiresMap; fCathodesMap = src.fCathodesMap; @@ -166,14 +245,15 @@ GlueXSensitiveDetectorFDC &GlueXSensitiveDetectorFDC::operator=(const GlueXSensitiveDetectorFDC::~GlueXSensitiveDetectorFDC() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorFDC::Initialize(G4HCofThisEvent* hce) { - fWiresMap = new + fWiresMap = new GlueXHitsMapFDCwire(SensitiveDetectorName, collectionName[0]); - fCathodesMap = new + fCathodesMap = new GlueXHitsMapFDCcathode(SensitiveDetectorName, collectionName[1]); fPointsMap = new GlueXHitsMapFDCpoint(SensitiveDetectorName, collectionName[2]); @@ -184,7 +264,7 @@ void GlueXSensitiveDetectorFDC::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorFDC::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -229,6 +309,8 @@ G4bool GlueXSensitiveDetectorFDC::ProcessHits(G4Step* step, "THIS SHOULD NEVER HAPPEN! drop this particle.\n"); return false; } + // Normally numeric identifiers start at 1, eg. layer, package, module + // but if it is an index counting from zero, add the "No" suffix. int packNo = package - 1; int module = 2 * packNo + ((layer - 1) / 3) + 1; int chamber = (module * 10) + ((layer - 1) % 3) + 1; @@ -244,8 +326,8 @@ G4bool GlueXSensitiveDetectorFDC::ProcessHits(G4Step* step, if (xlocal.perp() < wire_dead_zone_radius[packNo]) return false; - int wire = ceil((xlocal[0] - U_OF_WIRE_ZERO) / WIRE_SPACING + 0.5); - double xwire = U_OF_WIRE_ZERO + (wire - 1) * WIRE_SPACING; + int wire = ceil((xlocal[0] - U_OF_WIRE_ONE) / WIRE_SPACING + 0.5); + double xwire = U_OF_WIRE_ONE + (wire - 1) * WIRE_SPACING; double uwire = xinlocal[2]; double vwire = xinlocal[0] - xwire; double dradius = fabs(vwire * cosalpha - uwire * sinalpha); @@ -267,22 +349,22 @@ G4bool GlueXSensitiveDetectorFDC::ProcessHits(G4Step* step, if (lastPoint == 0 || lastPoint->track_ != trackID || lastPoint->chamber_ != chamber) { - GlueXHitFDCpoint* newPoint = new GlueXHitFDCpoint(chamber); + GlueXHitFDCpoint newPoint(chamber); + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.track_ = trackID; + newPoint.x_cm = xout[0]/cm; + newPoint.y_cm = xout[1]/cm; + newPoint.z_cm = xout[2]/cm; + newPoint.t_ns = tout/ns; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; + newPoint.dradius_cm = dradius/cm; + newPoint.dEdx_GeV_cm = dEdx/(GeV/cm); + newPoint.ptype_G3 = g3type; + newPoint.trackID_ = itrack; fPointsMap->add(key, newPoint); - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->track_ = trackID; - newPoint->x_cm = x[0]/cm; - newPoint->y_cm = x[1]/cm; - newPoint->z_cm = x[2]/cm; - newPoint->t_ns = t/ns; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; - newPoint->dradius_cm = dradius/cm; - newPoint->dEdx_GeV_cm = dEdx/(GeV/cm); - newPoint->ptype_G3 = g3type; - newPoint->trackID_ = itrack; } } @@ -291,39 +373,24 @@ G4bool GlueXSensitiveDetectorFDC::ProcessHits(G4Step* step, if (dEsum > 0) { double u0 = xinlocal[0]; double u1 = xoutlocal[0]; - int wire1 = ceil((u0 - U_OF_WIRE_ZERO) / WIRE_SPACING + 0.5); - int wire2 = ceil((u1 - U_OF_WIRE_ZERO) / WIRE_SPACING + 0.5); - - // Check that wire numbers are not out of range - if ((wire1 > WIRES_PER_PLANE && wire2 == WIRES_PER_PLANE) || - (wire2 > WIRES_PER_PLANE && wire1 == WIRES_PER_PLANE) ) - { - wire1 = wire2 = WIRES_PER_PLANE; - } - if ((wire1 == 0 && wire2 == 1) || (wire1 == 1 && wire2 == 0)) - { - wire1 = wire2 = 1; - } + int wire1 = ceil((u0 - U_OF_WIRE_ONE) / WIRE_SPACING + 0.5); + int wire2 = ceil((u1 - U_OF_WIRE_ONE) / WIRE_SPACING + 0.5); - // Make sure at least one wire number is valid + // Check that wire numbers are not out of range, + // making sure at least one wire number is valid if (wire1 > WIRES_PER_PLANE && wire2 > WIRES_PER_PLANE) return false; - else if (wire1 <= 0 && wire2 <= 0) + else if (wire1 < 1 && wire2 < 1) return false; - if (wire1 > WIRES_PER_PLANE) - wire1 = wire2; - else if (wire2 > WIRES_PER_PLANE) - wire2 = wire1; - if (wire1 == 0) - wire1 = wire2; - else if (wire2 == 0) - wire2 = wire1; + wire1 = (wire1 > WIRES_PER_PLANE)? WIRES_PER_PLANE : + (wire1 < 1)? 1 : wire1; + wire2 = (wire2 > WIRES_PER_PLANE)? WIRES_PER_PLANE : + (wire2 < 1)? 1 : wire2; int dwire = (wire1 < wire2)? 1 : -1; - // deal with the y-position for tracks crossing two cells - int sign = 1; - for (int wire = wire1; wire - dwire != wire2; wire += dwire) { - double xwire = U_OF_WIRE_ZERO + (wire - 1) * WIRE_SPACING; + // deal with the case of tracks crossing two cells + for (int wire = wire1; wire != wire2 + dwire; wire += dwire) { + double xwire = U_OF_WIRE_ONE + (wire - 1) * WIRE_SPACING; G4ThreeVector x0; G4ThreeVector x1; double dE; @@ -360,8 +427,9 @@ G4bool GlueXSensitiveDetectorFDC::ProcessHits(G4Step* step, int key = GlueXHitFDCwire::GetKey(chamber, wire); GlueXHitFDCwire *anode = (*fWiresMap)[key]; if (anode == 0) { - anode = new GlueXHitFDCwire(chamber, wire); - fWiresMap->add(key, anode); + GlueXHitFDCwire newanode(chamber, wire); + fWiresMap->add(key, newanode); + anode = (*fWiresMap)[key]; } // Add the hit to the hits vector, maintaining track time ordering, @@ -382,7 +450,7 @@ G4bool GlueXSensitiveDetectorFDC::ProcessHits(G4Step* step, hiter->dE_keV += dEsum/keV; hiter->t1_ns = tout/ns; hiter->x1_g = xout; - hiter->x1_l = xoutlocal; + hiter->x1_l = x1; } else if ((int)anode->hits.size() < MAX_HITS) { // create new hit @@ -402,9 +470,6 @@ G4bool GlueXSensitiveDetectorFDC::ProcessHits(G4Step* step, << "max hit count " << MAX_HITS << " exceeded, truncating!" << G4endl; } - - // deal with the y-position for tracks crossing two cells - sign *= -1; } } return true; @@ -438,7 +503,7 @@ void GlueXSensitiveDetectorFDC::EndOfEvent(G4HCofThisEvent*) G4cout << G4endl << "--------> Hits Collection: in this event there are " - << points->size() << " truth points in the CDC: " + << points->size() << " truth points in the FDC: " << G4endl; for (piter = points->begin(); piter != points->end(); ++piter) piter->second->Print(); @@ -472,14 +537,13 @@ void GlueXSensitiveDetectorFDC::EndOfEvent(G4HCofThisEvent*) // Merge multiple segments from a single track into one, and // apply the drift time algorithm to get a single hit time for each. - int chamberNo = witer->second->chamber_; - int wireNo = witer->second->wire_; - int module = chamberNo / 10; + int chamber = witer->second->chamber_; + int wire = witer->second->wire_; + int module = chamber / 10; int packNo = (module - 1) / 2; - int layer = chamberNo % 10; - int layerNo = layer - 1; - int glayer = 3 * layerNo + module - 1; - int global_wire_number = 96 * glayer + wireNo - 1; + int layer = chamber % 10; + int glayerNo = 3*(layer - 1) + module-1; + int global_wire_number = 96 * glayerNo + wire - 1; std::vector &splits = witer->second->hits; std::vector hits; while (splits.size() > 0) { @@ -500,9 +564,9 @@ void GlueXSensitiveDetectorFDC::EndOfEvent(G4HCofThisEvent*) // On average for each primary ion pair produced there are n_s_per_p // secondary ion pairs produced. - double xwire = U_OF_WIRE_ZERO + (wireNo - 1) * WIRE_SPACING; + double xwire = U_OF_WIRE_ONE + (wire - 1) * WIRE_SPACING; double dE = splits[0].dE_keV*keV; - if (dE > THRESH_KEV*keV) { + if (dE > THRESH_KEV*keV*0) { // Average number of primary ion pairs double n_p_mean = dE / W_EFF_PER_ION / (1 + N_SECOND_PER_PRIMARY); // number of primary ion pairs @@ -519,12 +583,12 @@ void GlueXSensitiveDetectorFDC::EndOfEvent(G4HCofThisEvent*) G4ThreeVector x((splits[0].x0_g + splits[0].x1_g) / 2); G4ThreeVector xlocal(x0 + alpha * dx); double tdrift; - int wire_fired = add_anode_hit(hits, splits[0], layerNo, + int wire_fired = add_anode_hit(hits, splits[0], layer, xwire, x, xlocal, dE, t, tdrift); if (wire_fired) { add_cathode_hit(splits[0], packNo, xwire, xlocal[1], - tdrift, n_p, chamberNo, module, layerNo, + tdrift, n_p, chamber, module, layer, global_wire_number); } } @@ -539,12 +603,12 @@ void GlueXSensitiveDetectorFDC::EndOfEvent(G4HCofThisEvent*) double u = G4UniformRand(); xlocal = x0 + u * (x1 - x0); double tdrift; - int wire_fired = add_anode_hit(hits, splits[0], layerNo, + int wire_fired = add_anode_hit(hits, splits[0], layer, xwire, x, xlocal, dE, t, tdrift); if (wire_fired) { add_cathode_hit(splits[0], packNo, xwire, xlocal[1], - tdrift, n_p, chamberNo, module, layerNo, + tdrift, n_p, chamber, module, layer, global_wire_number); } } @@ -659,12 +723,12 @@ void GlueXSensitiveDetectorFDC::EndOfEvent(G4HCofThisEvent*) hddm_s::FdcAnodeWireList anodes = citer->getFdcAnodeWires(); hddm_s::FdcAnodeWireList::iterator aiter; for (aiter = anodes.begin(); aiter != anodes.end(); ++aiter) { - if (aiter->getWire() == wireNo) + if (aiter->getWire() == wire) break; } if (aiter == anodes.end()) { anodes = citer->addFdcAnodeWires(1); - anodes(0).setWire(wireNo); + anodes(0).setWire(wire); aiter = anodes.begin(); } for (int ih=0; ih < (int)splits.size(); ++ih) { @@ -682,11 +746,11 @@ void GlueXSensitiveDetectorFDC::EndOfEvent(G4HCofThisEvent*) // Collect and output the cathodeTruthHits for (siter = strips->begin(); siter != strips->end(); ++siter) { - int chamberNo = siter->second->chamber_; + int chamber = siter->second->chamber_; int planeNo = siter->second->plane_; int stripNo = siter->second->strip_; - int module = chamberNo / 10; - int layer = chamberNo % 10; + int module = chamber / 10; + int layer = chamber % 10; std::vector &hits = siter->second->hits; std::vector::iterator hiter; if (fDrift_clusters) { @@ -795,7 +859,7 @@ void GlueXSensitiveDetectorFDC::EndOfEvent(G4HCofThisEvent*) } } - // Collect and output the strawTruthPoints + // Collect and output the fdcTruthPoints int last_chamber = -1; hddm_s::FdcTruthPoint *last_point = 0; @@ -932,8 +996,8 @@ void GlueXSensitiveDetectorFDC::add_cathode_hit( for (int plane=1; plane < 4; plane += 2) { double theta = (plane == 1)? M_PI-CATHODE_ROT_ANGLE : CATHODE_ROT_ANGLE; double cathode_u = -xwire * cos(theta) - yavalanche * sin(theta); - int strip1 = ceil((cathode_u - U_OF_STRIP_ZERO) / STRIP_SPACING + 0.5); - double cathode_u1 = (strip1 - 1) * STRIP_SPACING + U_OF_STRIP_ZERO; + int strip1 = ceil((cathode_u - U_OF_STRIP_ONE) / STRIP_SPACING + 0.5); + double cathode_u1 = (strip1 - 1) * STRIP_SPACING + U_OF_STRIP_ONE; double delta_u = cathode_u - cathode_u1; for (int node = -STRIP_NODES; node <= STRIP_NODES; node++) { // Induce charge on the strips according to the Mathieson @@ -958,8 +1022,9 @@ void GlueXSensitiveDetectorFDC::add_cathode_hit( int key = GlueXHitFDCcathode::GetKey(chamber, plane, strip); GlueXHitFDCcathode *cathode = (*fCathodesMap)[key]; if (cathode == 0) { - cathode = new GlueXHitFDCcathode(chamber, plane, strip); - fCathodesMap->add(key, cathode); + GlueXHitFDCcathode newcathode(chamber, plane, strip); + fCathodesMap->add(key, newcathode); + cathode = (*fCathodesMap)[key]; } std::vector::iterator hiter; for (hiter = cathode->hits.begin(); @@ -995,7 +1060,6 @@ int GlueXSensitiveDetectorFDC::add_anode_hit( // Get the magnetic field at this cluster position G4ThreeVector B = GlueXDetectorConstruction::GetInstance() ->GetMagneticField(xglobal, tesla); - double BmagT = B.mag(); double BrhoT = B.perp(); // Find the angle between the wire direction and the direction of the @@ -1005,13 +1069,12 @@ int GlueXSensitiveDetectorFDC::add_anode_hit( double phi = 0; if (BrhoT > 0) phi = acos((B[0] * wire_dir[0] + B[1] * wire_dir[1]) / BrhoT); - + // useful combinations of dx and dz - G4ThreeVector xyz(xlocal); - double dx = xyz[0] - xwire; + double dx = xlocal[0] - xwire; double dx2 = dx * dx; double dx4 = dx2 * dx2; - double dz = xyz[2]; + double dz = xlocal[2]; double dz2 = dz * dz; double dz4 = dz2 * dz2; @@ -1020,33 +1083,55 @@ int GlueXSensitiveDetectorFDC::add_anode_hit( // due to the Lorentz force. double cm2 = cm * cm; double cm4 = cm2 * cm2; - xyz[1] += (-0.125 * B[2] * (1 - 0.048 * BrhoT)) * dx + - (-0.180 - 0.0129 * B[2]) * BrhoT * cos(phi) * xyz[2] + - (-0.000176 * dx * dx2 / (dz2 + 1e-30)); + xlocal[1] += (LORENTZ_NR_PAR1 * B[2] * (1 + LORENTZ_NR_PAR2 * BrhoT)) * dx + + (LORENTZ_NZ_PAR1 + LORENTZ_NZ_PAR2 * B[2]) * BrhoT * cos(phi) * xlocal[2] + + (-0.000176 * dx * dx2 / (dz2 + 0.001*cm2)); // Add transverse diffusion - xyz[1] += G4RandGauss::shoot() * - (0.01*cm * pow((dx2 + dz2)/cm2, 0.125) + 0.0061*cm * dx2/cm2); + xlocal[1] += G4RandGauss::shoot() * + (0.01*cm * pow((dx2 + dz2)/cm2, 0.125) + 0.0061*cm * dx2/cm2); // Do not use this cluster if the Lorentz force would deflect // the electrons outside the active region of the detector - if (sqrt(xyz[1] * xyz[1] + xwire * xwire) > ACTIVE_AREA_OUTER_RADIUS) + if (sqrt(xlocal[1] * xlocal[1] + xwire * xwire) > ACTIVE_AREA_OUTER_RADIUS) return 0; // Model the drift time and longitudinal diffusion as a function of // position of the cluster within the cell - double tdrift_unsmeared = 1086.0*ns * (1 + 0.039 * BmagT) * dx2/cm2 + + +#if OLD_FDC_DRIFT_TIME_MODEL + double tdrift_unsmeared = 1086.0*ns * (1 + 0.039 * B.mag()) * dx2/cm2 + 1068.0*ns * dz2/cm2 + (-2.675*ns / (dz2/cm2 + 0.001) + 2.4e4*ns * dz2/cm2) * dx4/cm4; - double dt = G4RandGauss::shoot() * - (39.44*ns * dx4/cm4 / (0.5 - dz2/cm2) + - 56.00*ns * dz4/cm4 / (0.5 - dx2/cm2) + - 0.01566*ns * dx4/cm4 / (dz4/cm4 + 0.002) / (0.251 - dx2/cm2)); +#else + double dradius = sqrt(dx2 + dz2); + int index = locate(drift_table_d_cm, drift_table_len, dradius/cm); + index = (index < drift_table_len - 3)? index : drift_table_len - 3; + double *dd = &drift_table_d_cm[index]; + double tt = 0.5; //ns + double dd10 = dd[1] - dd[0]; + double dd20 = dd[2] - dd[0]; + double dd21 = dd[2] - dd[1]; + double qa = tt*index; + double qb = (dd20/dd10 - 2*dd10/dd20) * tt/dd21; + double qc = (2/dd20 - 1/dd10) * tt/dd21; + double d0 = dradius/cm - dd[0]; + double tdrift_unsmeared = qa + qb*d0 + qc*d0*d0; +#endif + + // Apply small B-field dependence on the drift time + tdrift_unsmeared *= 1. + DRIFT_BSCALE_PAR1 + DRIFT_BSCALE_PAR2*B[2]*B[2]; // Minimum drift time for docas near wire (very crude approximation) double v_max = 0.08*cm/ns; // guess for now based on Garfield, near wire - double dradius = sqrt(dx2 + dz2); double tmin = dradius / v_max; + + // longitidinal diffusion, derived from Garfield calculations + double dt = (G4RandGauss::shoot() - 0.5) * + (39.44*ns * dx4/cm4 / (0.5 - dz2/cm2) + + 56.00*ns * dz4/cm4 / (0.5 - dx2/cm2) + + 0.01566*ns * dx4/cm4 / (dz4/cm4 + 0.002) / (0.251 - dx2/cm2)); + double tdrift_smeared = tdrift_unsmeared + dt; if (tdrift_smeared < tmin) { tdrift_smeared = tmin; @@ -1160,10 +1245,11 @@ void GlueXSensitiveDetectorFDC::polint(double *xa, double *ya, int n, free(d); } -void locate(double *xx, int n, double x, int *j) +int GlueXSensitiveDetectorFDC::locate(double *xx, int n, double x) { // Locate a position in array xx of value x + int j; int ju; int jm; int jl; @@ -1180,11 +1266,12 @@ void locate(double *xx, int n, double x, int *j) ju = jm; } if (x == xx[0]) - *j = 0; + j = 0; else if (x == xx[n-1]) - *j = n-2; + j = n-2; else - *j = jl; + j = jl; + return j; } int GlueXSensitiveDetectorFDC::GetIdent(std::string div, @@ -1204,10 +1291,9 @@ int GlueXSensitiveDetectorFDC::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorFDC.hh b/src/GlueXSensitiveDetectorFDC.hh index 2f27b08..8a7ead3 100644 --- a/src/GlueXSensitiveDetectorFDC.hh +++ b/src/GlueXSensitiveDetectorFDC.hh @@ -54,14 +54,14 @@ class GlueXSensitiveDetectorFDC : public G4VSensitiveDetector int n_p, int chamber, int module, int layer, int global_wire_number); void polint(double *xa, double *ya, int n, double x, double *y, double *dy); - void locate(float *xx, int n, float x, int *j); + int locate(double *xx, int n, double x); private: GlueXHitsMapFDCwire* fWiresMap; GlueXHitsMapFDCcathode* fCathodesMap; GlueXHitsMapFDCpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static const double ELECTRON_CHARGE; static double DRIFT_SPEED; @@ -71,10 +71,10 @@ class GlueXSensitiveDetectorFDC : public G4VSensitiveDetector static int WIRES_PER_PLANE; static double WIRE_SPACING; static double STRIP_SPACING; - static double U_OF_WIRE_ZERO; + static double U_OF_WIRE_ONE; static int STRIPS_PER_PLANE; static double CATHODE_ROT_ANGLE; - static double U_OF_STRIP_ZERO; + static double U_OF_STRIP_ONE; static double STRIP_GAP; static double K2; static double STRIP_NODES; @@ -88,11 +88,24 @@ class GlueXSensitiveDetectorFDC : public G4VSensitiveDetector static int N_SECOND_PER_PRIMARY; static int MAX_HITS; + static double LORENTZ_NR_PAR1; + static double LORENTZ_NR_PAR2; + static double LORENTZ_NZ_PAR1; + static double LORENTZ_NZ_PAR2; + static double DRIFT_RES_PARMS[3]; + static double DRIFT_FUNC_PARMS[6]; + static double DRIFT_BSCALE_PAR1; + static double DRIFT_BSCALE_PAR2; + static int fDrift_clusters; static double wire_dead_zone_radius[4]; static double strip_dead_zone_radius[4]; + static int drift_table_len; + static double *drift_table_t_ns; + static double *drift_table_d_cm; + static int instanceCount; static G4Mutex fMutex; }; diff --git a/src/GlueXSensitiveDetectorFMWPC.cc b/src/GlueXSensitiveDetectorFMWPC.cc index 42d5cc6..178b32d 100644 --- a/src/GlueXSensitiveDetectorFMWPC.cc +++ b/src/GlueXSensitiveDetectorFMWPC.cc @@ -32,8 +32,6 @@ double GlueXSensitiveDetectorFMWPC::THRESH_KEV = 0.; int GlueXSensitiveDetectorFMWPC::instanceCount = 0; G4Mutex GlueXSensitiveDetectorFMWPC::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorFMWPC::fVolumeTable; - GlueXSensitiveDetectorFMWPC::GlueXSensitiveDetectorFMWPC(const G4String& name) : G4VSensitiveDetector(name), fWireHitsMap(0), fPointsMap(0) @@ -70,12 +68,14 @@ GlueXSensitiveDetectorFMWPC::GlueXSensitiveDetectorFMWPC( : G4VSensitiveDetector(src), fWireHitsMap(src.fWireHitsMap), fPointsMap(src.fPointsMap) { + G4AutoLock wirerier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorFMWPC &GlueXSensitiveDetectorFMWPC::operator=(const GlueXSensitiveDetectorFMWPC &src) { + G4AutoLock wirerier(&fMutex); *(G4VSensitiveDetector*)this = src; fWireHitsMap = src.fWireHitsMap; fPointsMap = src.fPointsMap; @@ -84,12 +84,13 @@ GlueXSensitiveDetectorFMWPC &GlueXSensitiveDetectorFMWPC::operator=(const GlueXSensitiveDetectorFMWPC::~GlueXSensitiveDetectorFMWPC() { + G4AutoLock wirerier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorFMWPC::Initialize(G4HCofThisEvent* hce) { - fWireHitsMap = new + fWireHitsMap = new GlueXHitsMapFMWPCwire(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapFMWPCpoint(SensitiveDetectorName, collectionName[1]); @@ -99,7 +100,7 @@ void GlueXSensitiveDetectorFMWPC::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorFMWPC::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -146,22 +147,22 @@ G4bool GlueXSensitiveDetectorFMWPC::ProcessHits(G4Step* step, fabs(lastPoint->y_cm - x[1]/cm) > 2. || fabs(lastPoint->z_cm - x[2]/cm) > 2.) { - GlueXHitFMWPCpoint* newPoint = new GlueXHitFMWPCpoint(); - fPointsMap->add(key, newPoint); int pdgtype = track->GetDynamicParticle()->GetPDGcode(); int g3type = GlueXPrimaryGeneratorAction::ConvertPdgToGeant3(pdgtype); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->x_cm = x[0]/cm; - newPoint->y_cm = x[1]/cm; - newPoint->z_cm = x[2]/cm; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; + GlueXHitFMWPCpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.x_cm = x[0]/cm; + newPoint.y_cm = x[1]/cm; + newPoint.z_cm = x[2]/cm; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; + fPointsMap->add(key, newPoint); } } @@ -195,8 +196,9 @@ G4bool GlueXSensitiveDetectorFMWPC::ProcessHits(G4Step* step, int key = GlueXHitFMWPCwire::GetKey(layer, wire); GlueXHitFMWPCwire *counter = (*fWireHitsMap)[key]; if (counter == 0) { - counter = new GlueXHitFMWPCwire(layer, wire); - fWireHitsMap->add(key, counter); + GlueXHitFMWPCwire newwire(layer, wire); + fWireHitsMap->add(key, newwire); + counter = (*fWireHitsMap)[key]; } // Add the hit to the hits vector, maintaining strict time ordering @@ -342,10 +344,9 @@ int GlueXSensitiveDetectorFMWPC::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorFMWPC.hh b/src/GlueXSensitiveDetectorFMWPC.hh index 32a5fcc..4ad6eab 100644 --- a/src/GlueXSensitiveDetectorFMWPC.hh +++ b/src/GlueXSensitiveDetectorFMWPC.hh @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorFMWPC : public G4VSensitiveDetector GlueXHitsMapFMWPCwire* fWireHitsMap; GlueXHitsMapFMWPCpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static double TWO_HIT_TIME_RESOL; diff --git a/src/GlueXSensitiveDetectorFTOF.cc b/src/GlueXSensitiveDetectorFTOF.cc index 244587f..5e073c5 100644 --- a/src/GlueXSensitiveDetectorFTOF.cc +++ b/src/GlueXSensitiveDetectorFTOF.cc @@ -43,8 +43,6 @@ double GlueXSensitiveDetectorFTOF::THRESH_MEV = 0.; int GlueXSensitiveDetectorFTOF::instanceCount = 0; G4Mutex GlueXSensitiveDetectorFTOF::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorFTOF::fVolumeTable; - GlueXSensitiveDetectorFTOF::GlueXSensitiveDetectorFTOF(const G4String& name) : G4VSensitiveDetector(name), fBarHitsMap(0), fPointsMap(0) @@ -88,12 +86,14 @@ GlueXSensitiveDetectorFTOF::GlueXSensitiveDetectorFTOF( : G4VSensitiveDetector(src), fBarHitsMap(src.fBarHitsMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorFTOF &GlueXSensitiveDetectorFTOF::operator=(const GlueXSensitiveDetectorFTOF &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fBarHitsMap = src.fBarHitsMap; fPointsMap = src.fPointsMap; @@ -102,12 +102,13 @@ GlueXSensitiveDetectorFTOF &GlueXSensitiveDetectorFTOF::operator=(const GlueXSensitiveDetectorFTOF::~GlueXSensitiveDetectorFTOF() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorFTOF::Initialize(G4HCofThisEvent* hce) { - fBarHitsMap = new + fBarHitsMap = new GlueXHitsMapFTOFbar(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapFTOFpoint(SensitiveDetectorName, collectionName[1]); @@ -117,7 +118,7 @@ void GlueXSensitiveDetectorFTOF::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorFTOF::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -153,7 +154,13 @@ G4bool GlueXSensitiveDetectorFTOF::ProcessHits(G4Step* step, int plane = GetIdent("plane", touch); int column = GetIdent("column", touch); int barNo = GetIdent("row", touch); - barNo = (barNo > 44)? barNo - 23 : barNo; + int barIndex = (column < 2)? barNo : GetIdent("paired_row", touch); + if (barIndex < 1) { + G4cerr << "GlueXSensitiveDetectorFTOF::ProcessHits error - " + << "hdds geometry for FTOF is missing paired_row identifier, " + << "cannot continue!" << G4endl; + exit(1); + } G4Track *track = step->GetTrack(); G4int trackID = track->GetTrackID(); int pdgtype = track->GetDynamicParticle()->GetPDGcode(); @@ -170,31 +177,32 @@ G4bool GlueXSensitiveDetectorFTOF::ProcessHits(G4Step* step, fabs(lastPoint->y_cm - x[1]/cm) > 2. || fabs(lastPoint->z_cm - x[2]/cm) > 2.) { - GlueXHitFTOFpoint* newPoint = new GlueXHitFTOFpoint(); + GlueXHitFTOFpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.x_cm = x[0]/cm; + newPoint.y_cm = x[1]/cm; + newPoint.z_cm = x[2]/cm; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; fPointsMap->add(key, newPoint); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->x_cm = x[0]/cm; - newPoint->y_cm = x[1]/cm; - newPoint->z_cm = x[2]/cm; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; } } // Post the hit to the hits map, ordered by plane,bar,end index if (dEsum > 0) { - int key = GlueXHitFTOFbar::GetKey(plane, barNo); + int key = GlueXHitFTOFbar::GetKey(plane, barIndex); GlueXHitFTOFbar *counter = (*fBarHitsMap)[key]; if (counter == 0) { - counter = new GlueXHitFTOFbar(plane, barNo); - fBarHitsMap->add(key, counter); + GlueXHitFTOFbar newcounter(plane, barIndex); + fBarHitsMap->add(key, newcounter); + counter = (*fBarHitsMap)[key]; } double dist = x[1]; // do not use local coordinate for x and y @@ -426,7 +434,7 @@ void GlueXSensitiveDetectorFTOF::EndOfEvent(G4HCofThisEvent*) hitview.addForwardTOFs(); hddm_s::ForwardTOF &forwardTOF = hitview.getForwardTOF(); - // Collect and output the tofTruthHits + // Collect and output the ftofTruthHits for (siter = bars->begin(); siter != bars->end(); ++siter) { std::vector &hits = siter->second->hits; // apply a pulse height threshold cut @@ -487,7 +495,7 @@ void GlueXSensitiveDetectorFTOF::EndOfEvent(G4HCofThisEvent*) } } - // Collect and output the barTruthPoints + // Collect and output the ftofTruthPoints for (piter = points->begin(); piter != points->end(); ++piter) { hddm_s::FtofTruthPointList point = forwardTOF.addFtofTruthPoints(1); point(0).setPrimary(piter->second->primary_); @@ -523,10 +531,9 @@ int GlueXSensitiveDetectorFTOF::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorFTOF.hh b/src/GlueXSensitiveDetectorFTOF.hh index 7c5f87a..04094ee 100644 --- a/src/GlueXSensitiveDetectorFTOF.hh +++ b/src/GlueXSensitiveDetectorFTOF.hh @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorFTOF : public G4VSensitiveDetector GlueXHitsMapFTOFbar* fBarHitsMap; GlueXHitsMapFTOFpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static int MAX_HITS_PER_BAR; diff --git a/src/GlueXSensitiveDetectorGCAL.cc b/src/GlueXSensitiveDetectorGCAL.cc index 791d713..d53f27f 100644 --- a/src/GlueXSensitiveDetectorGCAL.cc +++ b/src/GlueXSensitiveDetectorGCAL.cc @@ -37,8 +37,6 @@ double GlueXSensitiveDetectorGCAL::THRESH_MEV = 30.; int GlueXSensitiveDetectorGCAL::instanceCount = 0; G4Mutex GlueXSensitiveDetectorGCAL::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorGCAL::fVolumeTable; - GlueXSensitiveDetectorGCAL::GlueXSensitiveDetectorGCAL(const G4String& name) : G4VSensitiveDetector(name), fBlockHitsMap(0), fPointsMap(0) @@ -75,12 +73,14 @@ GlueXSensitiveDetectorGCAL::GlueXSensitiveDetectorGCAL( : G4VSensitiveDetector(src), fBlockHitsMap(src.fBlockHitsMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorGCAL &GlueXSensitiveDetectorGCAL::operator=(const GlueXSensitiveDetectorGCAL &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fBlockHitsMap = src.fBlockHitsMap; fPointsMap = src.fPointsMap; @@ -89,12 +89,13 @@ GlueXSensitiveDetectorGCAL &GlueXSensitiveDetectorGCAL::operator=(const GlueXSensitiveDetectorGCAL::~GlueXSensitiveDetectorGCAL() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorGCAL::Initialize(G4HCofThisEvent* hce) { - fBlockHitsMap = new + fBlockHitsMap = new GlueXHitsMapGCALblock(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapGCALpoint(SensitiveDetectorName, collectionName[1]); @@ -104,7 +105,7 @@ void GlueXSensitiveDetectorGCAL::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorGCAL::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -146,23 +147,23 @@ G4bool GlueXSensitiveDetectorGCAL::ProcessHits(G4Step* step, if (trackinfo->GetGlueXHistory() == 0 && itrack > 0 && xin.dot(pin) > 0 && Ein/MeV > THRESH_MEV) { - GlueXHitGCALpoint* newPoint = new GlueXHitGCALpoint(); - G4int key = fPointsMap->entries(); - fPointsMap->add(key, newPoint); int pdgtype = track->GetDynamicParticle()->GetPDGcode(); int g3type = GlueXPrimaryGeneratorAction::ConvertPdgToGeant3(pdgtype); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->z_cm = x[2]/cm; - newPoint->r_cm = x.perp()/cm; - newPoint->phi_rad = x.phi(); - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; + GlueXHitGCALpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.z_cm = x[2]/cm; + newPoint.r_cm = x.perp()/cm; + newPoint.phi_rad = x.phi(); + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; + G4int key = fPointsMap->entries(); + fPointsMap->add(key, newPoint); trackinfo->SetGlueXHistory(3); } @@ -172,8 +173,9 @@ G4bool GlueXSensitiveDetectorGCAL::ProcessHits(G4Step* step, int key = GlueXHitGCALblock::GetKey(module); GlueXHitGCALblock *block = (*fBlockHitsMap)[key]; if (block == 0) { - block = new GlueXHitGCALblock(module); - fBlockHitsMap->add(key, block); + GlueXHitGCALblock newblock(module); + fBlockHitsMap->add(key, newblock); + block = (*fBlockHitsMap)[key]; } double dist = 0.5 * LENGTH_OF_BLOCK - xlocal[2]; double dEcorr = dEsum * exp(-dist / ATTENUATION_LENGTH); @@ -301,7 +303,7 @@ void GlueXSensitiveDetectorGCAL::EndOfEvent(G4HCofThisEvent*) } int GlueXSensitiveDetectorGCAL::GetIdent(std::string div, - const G4VTouchable *touch) + const G4VTouchable *touch) { const HddsG4Builder* bldr = GlueXDetectorConstruction::GetBuilder(); std::map >::const_iterator iter; @@ -317,10 +319,9 @@ int GlueXSensitiveDetectorGCAL::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorGCAL.hh b/src/GlueXSensitiveDetectorGCAL.hh index 6fe477e..c07a356 100644 --- a/src/GlueXSensitiveDetectorGCAL.hh +++ b/src/GlueXSensitiveDetectorGCAL.hh @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorGCAL : public G4VSensitiveDetector GlueXHitsMapGCALblock* fBlockHitsMap; GlueXHitsMapGCALpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static double ATTENUATION_LENGTH; diff --git a/src/GlueXSensitiveDetectorPS.cc b/src/GlueXSensitiveDetectorPS.cc index 321372c..4804e35 100644 --- a/src/GlueXSensitiveDetectorPS.cc +++ b/src/GlueXSensitiveDetectorPS.cc @@ -35,8 +35,6 @@ int GlueXSensitiveDetectorPS::NUM_COLUMNS_PER_ARM = 145; int GlueXSensitiveDetectorPS::instanceCount = 0; G4Mutex GlueXSensitiveDetectorPS::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorPS::fVolumeTable; - GlueXSensitiveDetectorPS::GlueXSensitiveDetectorPS(const G4String& name) : G4VSensitiveDetector(name), fTileHitsMap(0), fPointsMap(0) @@ -73,12 +71,14 @@ GlueXSensitiveDetectorPS::GlueXSensitiveDetectorPS( : G4VSensitiveDetector(src), fTileHitsMap(src.fTileHitsMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorPS &GlueXSensitiveDetectorPS::operator=(const GlueXSensitiveDetectorPS &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fTileHitsMap = src.fTileHitsMap; fPointsMap = src.fPointsMap; @@ -87,12 +87,13 @@ GlueXSensitiveDetectorPS &GlueXSensitiveDetectorPS::operator=(const GlueXSensitiveDetectorPS::~GlueXSensitiveDetectorPS() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorPS::Initialize(G4HCofThisEvent* hce) { - fTileHitsMap = new + fTileHitsMap = new GlueXHitsMapPStile(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapPSpoint(SensitiveDetectorName, collectionName[1]); @@ -102,7 +103,7 @@ void GlueXSensitiveDetectorPS::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorPS::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -157,23 +158,23 @@ G4bool GlueXSensitiveDetectorPS::ProcessHits(G4Step* step, fabs(lastPoint->y_cm - x[1]/cm) > 5.0 || fabs(lastPoint->z_cm - x[2]/cm) > 5.0) { - GlueXHitPSpoint* newPoint = new GlueXHitPSpoint(); + GlueXHitPSpoint newPoint; + newPoint.arm_ = arm; + newPoint.column_ = column; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.x_cm = x[0]/cm; + newPoint.y_cm = x[1]/cm; + newPoint.z_cm = x[2]/cm; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; + newPoint.dEdx_GeV_cm = dEdx/(GeV/cm); fPointsMap->add(key, newPoint); - newPoint->arm_ = arm; - newPoint->column_ = column; - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->x_cm = x[0]/cm; - newPoint->y_cm = x[1]/cm; - newPoint->z_cm = x[2]/cm; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; - newPoint->dEdx_GeV_cm = dEdx/(GeV/cm); } } @@ -183,8 +184,9 @@ G4bool GlueXSensitiveDetectorPS::ProcessHits(G4Step* step, int key = GlueXHitPStile::GetKey(arm, column); GlueXHitPStile *tile = (*fTileHitsMap)[key]; if (tile == 0) { - tile = new GlueXHitPStile(arm, column); - fTileHitsMap->add(key, tile); + GlueXHitPStile newtile(arm, column); + fTileHitsMap->add(key, newtile); + tile = (*fTileHitsMap)[key]; } // Add the hit to the hits vector, maintaining strict time ordering @@ -332,10 +334,9 @@ int GlueXSensitiveDetectorPS::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorPS.hh b/src/GlueXSensitiveDetectorPS.hh index db2d411..f0f5b23 100644 --- a/src/GlueXSensitiveDetectorPS.hh +++ b/src/GlueXSensitiveDetectorPS.hh @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorPS : public G4VSensitiveDetector GlueXHitsMapPStile* fTileHitsMap; GlueXHitsMapPSpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static int NUM_COLUMNS_PER_ARM; diff --git a/src/GlueXSensitiveDetectorPSC.cc b/src/GlueXSensitiveDetectorPSC.cc index 7cd7892..526f2d1 100644 --- a/src/GlueXSensitiveDetectorPSC.cc +++ b/src/GlueXSensitiveDetectorPSC.cc @@ -35,8 +35,6 @@ int GlueXSensitiveDetectorPSC::NUM_MODULES_PER_ARM = 8; int GlueXSensitiveDetectorPSC::instanceCount = 0; G4Mutex GlueXSensitiveDetectorPSC::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorPSC::fVolumeTable; - GlueXSensitiveDetectorPSC::GlueXSensitiveDetectorPSC(const G4String& name) : G4VSensitiveDetector(name), fCounterHitsMap(0), fPointsMap(0) @@ -73,12 +71,14 @@ GlueXSensitiveDetectorPSC::GlueXSensitiveDetectorPSC( : G4VSensitiveDetector(src), fCounterHitsMap(src.fCounterHitsMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorPSC &GlueXSensitiveDetectorPSC::operator=(const GlueXSensitiveDetectorPSC &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fCounterHitsMap = src.fCounterHitsMap; fPointsMap = src.fPointsMap; @@ -87,12 +87,13 @@ GlueXSensitiveDetectorPSC &GlueXSensitiveDetectorPSC::operator=(const GlueXSensitiveDetectorPSC::~GlueXSensitiveDetectorPSC() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorPSC::Initialize(G4HCofThisEvent* hce) { - fCounterHitsMap = new + fCounterHitsMap = new GlueXHitsMapPSCpaddle(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapPSCpoint(SensitiveDetectorName, collectionName[1]); @@ -102,7 +103,7 @@ void GlueXSensitiveDetectorPSC::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorPSC::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -157,23 +158,23 @@ G4bool GlueXSensitiveDetectorPSC::ProcessHits(G4Step* step, fabs(lastPoint->y_cm - x[1]/cm) > 5.0 || fabs(lastPoint->z_cm - x[2]/cm) > 5.0) { - GlueXHitPSCpoint* newPoint = new GlueXHitPSCpoint(); + GlueXHitPSCpoint newPoint; + newPoint.arm_ = arm; + newPoint.module_ = module; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.x_cm = x[0]/cm; + newPoint.y_cm = x[1]/cm; + newPoint.z_cm = x[2]/cm; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; + newPoint.dEdx_GeV_cm = dEdx/(GeV/cm); fPointsMap->add(key, newPoint); - newPoint->arm_ = arm; - newPoint->module_ = module; - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->x_cm = x[0]/cm; - newPoint->y_cm = x[1]/cm; - newPoint->z_cm = x[2]/cm; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; - newPoint->dEdx_GeV_cm = dEdx/(GeV/cm); } } @@ -183,8 +184,9 @@ G4bool GlueXSensitiveDetectorPSC::ProcessHits(G4Step* step, int key = GlueXHitPSCpaddle::GetKey(arm, module); GlueXHitPSCpaddle *paddle = (*fCounterHitsMap)[key]; if (paddle == 0) { - paddle = new GlueXHitPSCpaddle(arm, module); - fCounterHitsMap->add(key, paddle); + GlueXHitPSCpaddle newpaddle(arm, module); + fCounterHitsMap->add(key, newpaddle); + paddle = (*fCounterHitsMap)[key]; } // Add the hit to the hits vector, maintaining strict time ordering @@ -332,10 +334,9 @@ int GlueXSensitiveDetectorPSC::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorPSC.hh b/src/GlueXSensitiveDetectorPSC.hh index 34f571f..f82932f 100644 --- a/src/GlueXSensitiveDetectorPSC.hh +++ b/src/GlueXSensitiveDetectorPSC.hh @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorPSC : public G4VSensitiveDetector GlueXHitsMapPSCpaddle* fCounterHitsMap; GlueXHitsMapPSCpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static int NUM_MODULES_PER_ARM; diff --git a/src/GlueXSensitiveDetectorSTC.cc b/src/GlueXSensitiveDetectorSTC.cc index 13e13c6..da9d1a6 100644 --- a/src/GlueXSensitiveDetectorSTC.cc +++ b/src/GlueXSensitiveDetectorSTC.cc @@ -58,8 +58,6 @@ double GlueXSensitiveDetectorSTC::THRESH_MEV = 0.150; int GlueXSensitiveDetectorSTC::instanceCount = 0; G4Mutex GlueXSensitiveDetectorSTC::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorSTC::fVolumeTable; - GlueXSensitiveDetectorSTC::GlueXSensitiveDetectorSTC(const G4String& name) : G4VSensitiveDetector(name), fHitsMap(0), fPointsMap(0) @@ -108,14 +106,14 @@ GlueXSensitiveDetectorSTC::GlueXSensitiveDetectorSTC(const G4String& name) STRAIGHT_ATTENUATION_B[k] /= cm; BENDNOSE_ATTENUATION_B[k] /= cm; } - jcalib->Get("START_COUNTER/propagation_speed", values); + jcalib->Get("START_COUNTER/propagation_time_corr", values); for (unsigned int k=0; k < values.size(); ++k) { - STRAIGHT_PROPAGATION_A[k] = values[k].at("SC_STRAIGHT_PROPAGATION_A"); - STRAIGHT_PROPAGATION_B[k] = values[k].at("SC_STRAIGHT_PROPAGATION_B"); - BEND_PROPAGATION_A[k] = values[k].at("SC_BEND_PROPAGATION_A"); - BEND_PROPAGATION_B[k] = values[k].at("SC_BEND_PROPAGATION_B"); - NOSE_PROPAGATION_A[k] = values[k].at("SC_NOSE_PROPAGATION_A"); - NOSE_PROPAGATION_B[k] = values[k].at("SC_NOSE_PROPAGATION_B"); + STRAIGHT_PROPAGATION_A[k] = values[k].at("a"); + STRAIGHT_PROPAGATION_B[k] = values[k].at("b"); + BEND_PROPAGATION_A[k] = values[k].at("c"); + BEND_PROPAGATION_B[k] = values[k].at("d"); + NOSE_PROPAGATION_A[k] = values[k].at("e"); + NOSE_PROPAGATION_B[k] = values[k].at("f"); // A factors are in units of ns, B factors are ns/cm STRAIGHT_PROPAGATION_A[k] *= ns; STRAIGHT_PROPAGATION_B[k] *= ns/cm; @@ -134,12 +132,14 @@ GlueXSensitiveDetectorSTC::GlueXSensitiveDetectorSTC( : G4VSensitiveDetector(src), fHitsMap(src.fHitsMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorSTC &GlueXSensitiveDetectorSTC::operator=(const GlueXSensitiveDetectorSTC &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fHitsMap = src.fHitsMap; fPointsMap = src.fPointsMap; @@ -148,12 +148,13 @@ GlueXSensitiveDetectorSTC &GlueXSensitiveDetectorSTC::operator=(const GlueXSensitiveDetectorSTC::~GlueXSensitiveDetectorSTC() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorSTC::Initialize(G4HCofThisEvent* hce) { - fHitsMap = new + fHitsMap = new GlueXHitsMapSTCpaddle(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapSTCpoint(SensitiveDetectorName, collectionName[1]); @@ -163,7 +164,7 @@ void GlueXSensitiveDetectorSTC::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorSTC::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -214,22 +215,22 @@ G4bool GlueXSensitiveDetectorSTC::ProcessHits(G4Step* step, fabs(lastPoint->t_ns - t/ns) > 0.1 || fabs(lastPoint->z_cm - x[2]/cm) > 0.1) { - GlueXHitSTCpoint* newPoint = new GlueXHitSTCpoint(); + GlueXHitSTCpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.sector_ = sector; + newPoint.t_ns = t/ns; + newPoint.z_cm = x[2]/cm; + newPoint.r_cm = x.perp()/cm; + newPoint.phi_rad = x.phi(); + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; + newPoint.dEdx_GeV_cm = dEdx/(GeV/cm); fPointsMap->add(key, newPoint); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->sector_ = sector; - newPoint->t_ns = t/ns; - newPoint->z_cm = x[2]/cm; - newPoint->r_cm = x.perp()/cm; - newPoint->phi_rad = x.phi(); - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; - newPoint->dEdx_GeV_cm = dEdx/(GeV/cm); } } @@ -239,8 +240,9 @@ G4bool GlueXSensitiveDetectorSTC::ProcessHits(G4Step* step, int key = GlueXHitSTCpaddle::GetKey(sector); GlueXHitSTCpaddle *paddle = (*fHitsMap)[key]; if (paddle == 0) { - paddle = new GlueXHitSTCpaddle(sector); - fHitsMap->add(key, paddle); + GlueXHitSTCpaddle newpaddle(sector); + fHitsMap->add(key, newpaddle); + paddle = (*fHitsMap)[key]; } double dbent = 0.0; @@ -284,7 +286,6 @@ G4bool GlueXSensitiveDetectorSTC::ProcessHits(G4Step* step, return false; } - // Add the hit to the hits vector, maintaining strict time ordering int merge_hit = 0; @@ -397,7 +398,7 @@ void GlueXSensitiveDetectorSTC::EndOfEvent(G4HCofThisEvent*) } } - // Collect and output the paddleTruthPoints + // Collect and output the stcTruthPoints for (piter = points->begin(); piter != points->end(); ++piter) { hddm_s::StcTruthPointList point = startCntr.addStcTruthPoints(1); point(0).setE(piter->second->E_GeV); @@ -435,10 +436,9 @@ int GlueXSensitiveDetectorSTC::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorSTC.hh b/src/GlueXSensitiveDetectorSTC.hh index cd1e94e..a43f5d8 100644 --- a/src/GlueXSensitiveDetectorSTC.hh +++ b/src/GlueXSensitiveDetectorSTC.hh @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorSTC : public G4VSensitiveDetector GlueXHitsMapSTCpaddle* fHitsMap; GlueXHitsMapSTCpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static double ATTENUATION_LENGTH; diff --git a/src/GlueXSensitiveDetectorTPOL.cc b/src/GlueXSensitiveDetectorTPOL.cc index 1f4249d..58124e7 100644 --- a/src/GlueXSensitiveDetectorTPOL.cc +++ b/src/GlueXSensitiveDetectorTPOL.cc @@ -34,8 +34,6 @@ double GlueXSensitiveDetectorTPOL::THRESH_MEV = 0.050; int GlueXSensitiveDetectorTPOL::instanceCount = 0; G4Mutex GlueXSensitiveDetectorTPOL::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorTPOL::fVolumeTable; - GlueXSensitiveDetectorTPOL::GlueXSensitiveDetectorTPOL(const G4String& name) : G4VSensitiveDetector(name), fHitsMap(0), fPointsMap(0) @@ -72,12 +70,14 @@ GlueXSensitiveDetectorTPOL::GlueXSensitiveDetectorTPOL( : G4VSensitiveDetector(src), fHitsMap(src.fHitsMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorTPOL &GlueXSensitiveDetectorTPOL::operator=(const GlueXSensitiveDetectorTPOL &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fHitsMap = src.fHitsMap; fPointsMap = src.fPointsMap; @@ -86,12 +86,13 @@ GlueXSensitiveDetectorTPOL &GlueXSensitiveDetectorTPOL::operator=(const GlueXSensitiveDetectorTPOL::~GlueXSensitiveDetectorTPOL() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorTPOL::Initialize(G4HCofThisEvent* hce) { - fHitsMap = new + fHitsMap = new GlueXHitsMapTPOLwedge(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapTPOLpoint(SensitiveDetectorName, collectionName[1]); @@ -101,7 +102,7 @@ void GlueXSensitiveDetectorTPOL::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorTPOL::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -154,20 +155,20 @@ G4bool GlueXSensitiveDetectorTPOL::ProcessHits(G4Step* step, (fabs(lastPoint->r_cm - x.perp()/cm) > 0.1 && fabs(lastPoint->phi_rad - x.phi()) > 0.1) ) { - GlueXHitTPOLpoint* newPoint = new GlueXHitTPOLpoint(); + GlueXHitTPOLpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = itrack; + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.phi_rad = x.phi(); + newPoint.r_cm = x.perp()/cm; + newPoint.t_ns = t/ns; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; + newPoint.dEdx_GeV_cm = dEdx/(GeV/cm); fPointsMap->add(key, newPoint); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = itrack; - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->phi_rad = x.phi(); - newPoint->r_cm = x.perp()/cm; - newPoint->t_ns = t/ns; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; - newPoint->dEdx_GeV_cm = dEdx/(GeV/cm); } } @@ -177,8 +178,9 @@ G4bool GlueXSensitiveDetectorTPOL::ProcessHits(G4Step* step, int key = GlueXHitTPOLwedge::GetKey(sector, ring); GlueXHitTPOLwedge *wedge = (*fHitsMap)[key]; if (wedge == 0) { - wedge = new GlueXHitTPOLwedge(sector, ring); - fHitsMap->add(key, wedge); + GlueXHitTPOLwedge newwedge(sector, ring); + fHitsMap->add(key, newwedge); + wedge = (*fHitsMap)[key]; } // Add the hit to the hits vector, maintaining strict time ordering @@ -294,7 +296,7 @@ void GlueXSensitiveDetectorTPOL::EndOfEvent(G4HCofThisEvent*) } } - // Collect and output the wedgeTruthPoints + // Collect and output the tpolTruthPoints for (piter = points->begin(); piter != points->end(); ++piter) { hddm_s::TpolTruthPointList point = polarimeter.addTpolTruthPoints(1); point(0).setE(piter->second->E_GeV); @@ -330,10 +332,9 @@ int GlueXSensitiveDetectorTPOL::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorTPOL.hh b/src/GlueXSensitiveDetectorTPOL.hh index 7d90ac9..36d5f1c 100644 --- a/src/GlueXSensitiveDetectorTPOL.hh +++ b/src/GlueXSensitiveDetectorTPOL.hh @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorTPOL : public G4VSensitiveDetector GlueXHitsMapTPOLwedge* fHitsMap; GlueXHitsMapTPOLpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static double TWO_HIT_TIME_RESOL; diff --git a/src/GlueXSensitiveDetectorUPV.cc b/src/GlueXSensitiveDetectorUPV.cc index be8d9f1..67fd042 100644 --- a/src/GlueXSensitiveDetectorUPV.cc +++ b/src/GlueXSensitiveDetectorUPV.cc @@ -36,8 +36,6 @@ double GlueXSensitiveDetectorUPV::THRESH_MEV = 5.; int GlueXSensitiveDetectorUPV::instanceCount = 0; G4Mutex GlueXSensitiveDetectorUPV::fMutex = G4MUTEX_INITIALIZER; -std::map GlueXSensitiveDetectorUPV::fVolumeTable; - GlueXSensitiveDetectorUPV::GlueXSensitiveDetectorUPV(const G4String& name) : G4VSensitiveDetector(name), fBarHitsMap(0), fPointsMap(0) @@ -74,12 +72,14 @@ GlueXSensitiveDetectorUPV::GlueXSensitiveDetectorUPV( : G4VSensitiveDetector(src), fBarHitsMap(src.fBarHitsMap), fPointsMap(src.fPointsMap) { + G4AutoLock barrier(&fMutex); ++instanceCount; } GlueXSensitiveDetectorUPV &GlueXSensitiveDetectorUPV::operator=(const GlueXSensitiveDetectorUPV &src) { + G4AutoLock barrier(&fMutex); *(G4VSensitiveDetector*)this = src; fBarHitsMap = src.fBarHitsMap; fPointsMap = src.fPointsMap; @@ -88,12 +88,13 @@ GlueXSensitiveDetectorUPV &GlueXSensitiveDetectorUPV::operator=(const GlueXSensitiveDetectorUPV::~GlueXSensitiveDetectorUPV() { + G4AutoLock barrier(&fMutex); --instanceCount; } void GlueXSensitiveDetectorUPV::Initialize(G4HCofThisEvent* hce) { - fBarHitsMap = new + fBarHitsMap = new GlueXHitsMapUPVbar(SensitiveDetectorName, collectionName[0]); fPointsMap = new GlueXHitsMapUPVpoint(SensitiveDetectorName, collectionName[1]); @@ -103,7 +104,7 @@ void GlueXSensitiveDetectorUPV::Initialize(G4HCofThisEvent* hce) } G4bool GlueXSensitiveDetectorUPV::ProcessHits(G4Step* step, - G4TouchableHistory* unused) + G4TouchableHistory* ROhist) { double dEsum = step->GetTotalEnergyDeposit(); if (dEsum == 0) @@ -151,22 +152,22 @@ G4bool GlueXSensitiveDetectorUPV::ProcessHits(G4Step* step, fabs(lastPoint->y_cm - x[1]/cm) > 2. || fabs(lastPoint->z_cm - x[2]/cm) > 2.) { - GlueXHitUPVpoint* newPoint = new GlueXHitUPVpoint(); - fPointsMap->add(key, newPoint); int pdgtype = track->GetDynamicParticle()->GetPDGcode(); int g3type = GlueXPrimaryGeneratorAction::ConvertPdgToGeant3(pdgtype); - newPoint->ptype_G3 = g3type; - newPoint->track_ = trackID; - newPoint->trackID_ = trackinfo->GetGlueXTrackID(); - newPoint->primary_ = (track->GetParentID() == 0); - newPoint->t_ns = t/ns; - newPoint->x_cm = x[0]/cm; - newPoint->y_cm = x[1]/cm; - newPoint->z_cm = x[2]/cm; - newPoint->px_GeV = pin[0]/GeV; - newPoint->py_GeV = pin[1]/GeV; - newPoint->pz_GeV = pin[2]/GeV; - newPoint->E_GeV = Ein/GeV; + GlueXHitUPVpoint newPoint; + newPoint.ptype_G3 = g3type; + newPoint.track_ = trackID; + newPoint.trackID_ = trackinfo->GetGlueXTrackID(); + newPoint.primary_ = (track->GetParentID() == 0); + newPoint.t_ns = t/ns; + newPoint.x_cm = x[0]/cm; + newPoint.y_cm = x[1]/cm; + newPoint.z_cm = x[2]/cm; + newPoint.px_GeV = pin[0]/GeV; + newPoint.py_GeV = pin[1]/GeV; + newPoint.pz_GeV = pin[2]/GeV; + newPoint.E_GeV = Ein/GeV; + fPointsMap->add(key, newPoint); } } @@ -176,8 +177,9 @@ G4bool GlueXSensitiveDetectorUPV::ProcessHits(G4Step* step, int key = GlueXHitUPVbar::GetKey(layer, row); GlueXHitUPVbar *counter = (*fBarHitsMap)[key]; if (counter == 0) { - counter = new GlueXHitUPVbar(layer, row); - fBarHitsMap->add(key, counter); + GlueXHitUPVbar newcounter(layer, row); + fBarHitsMap->add(key, newcounter); + counter = (*fBarHitsMap)[key]; } double dxleft = xlocal[0]; @@ -386,10 +388,9 @@ int GlueXSensitiveDetectorUPV::GetIdent(std::string div, } identifiers = &Refsys::fIdentifierTable[volId]; if ((iter = identifiers->find(div)) != identifiers->end()) { - if (dynamic_cast(pvol)) - return iter->second[pvol->GetCopyNo() - 1]; - else - return iter->second[pvol->GetCopyNo()]; + int copyNum = touch->GetCopyNumber(depth); + copyNum += (dynamic_cast(pvol))? -1 : 0; + return iter->second[copyNum]; } } return -1; diff --git a/src/GlueXSensitiveDetectorUPV.hh b/src/GlueXSensitiveDetectorUPV.hh index eb0dc8c..e16c112 100644 --- a/src/GlueXSensitiveDetectorUPV.hh +++ b/src/GlueXSensitiveDetectorUPV.hh @@ -38,7 +38,7 @@ class GlueXSensitiveDetectorUPV : public G4VSensitiveDetector GlueXHitsMapUPVbar* fBarHitsMap; GlueXHitsMapUPVpoint* fPointsMap; - static std::map fVolumeTable; + std::map fVolumeTable; static int MAX_HITS; static double ATTENUATION_LENGTH; diff --git a/src/GlueXStackingAction.cc b/src/GlueXStackingAction.cc index d735289..b348cf7 100644 --- a/src/GlueXStackingAction.cc +++ b/src/GlueXStackingAction.cc @@ -7,10 +7,21 @@ #include "GlueXStackingAction.hh" #include "GlueXUserOptions.hh" #include "GlueXUserTrackInformation.hh" +#include "GlueXSensitiveDetectorDIRC.hh" #include "G4Track.hh" #include "G4ios.hh" #include "G4ParticleTable.hh" +#include "TMath.h" +#include "G4TransportationManager.hh" +#include "G4PhysicalVolumeStore.hh" + +#ifdef DIRC_MONITORING_HISTOS +#include "TH1.h" +#include "TCanvas.h" +TH1F *hbouncez = new TH1F("hbouncez",";bounces along z [#];entries [#]",1000,0,2000); +TH1F *hbouncey = new TH1F("hbouncey",";bounces along y [#];entries [#]",1000,0,2000); +#endif GlueXStackingAction::GlueXStackingAction() { @@ -41,10 +52,28 @@ GlueXStackingAction::GlueXStackingAction() if (user_opts->Find("NOSECONDARIES", opt)) { nosecondaries = (opt[1] != 0); } + + fBarEnd = 0; + G4PhysicalVolumeStore* pvStore = G4PhysicalVolumeStore::GetInstance(); + for (size_t i=0; isize(); i++) { + if ((*pvStore)[i]->GetName()=="QZWN") { + fBarEnd = fabs((*pvStore)[i]->GetTranslation().x()); + } + } } GlueXStackingAction::~GlueXStackingAction() -{} +{ +#ifdef DIRC_MONITORING_HISTOS + TCanvas *c = new TCanvas("c","c",800,400); + hbouncez->Draw(); + c->Print("cbounces_z.png"); + c->Print("cbounces_z.C"); + hbouncey->Draw(); + c->Print("cbounces_y.png"); + c->Print("cbounces_y.C"); +#endif +} G4ClassificationOfNewTrack GlueXStackingAction::ClassifyNewTrack( const G4Track *aTrack) @@ -71,6 +100,62 @@ G4ClassificationOfNewTrack GlueXStackingAction::ClassifyNewTrack( if (nosecondaries && aTrack->GetParentID() != 0) return fKill; + // apply detection efficiency for the DIRC at production stage: + G4String ParticleName = aTrack->GetDynamicParticle()->GetParticleDefinition()->GetParticleName(); + if (aTrack->GetParentID() != 0) { // particle is secondary + if (ParticleName == "opticalphoton") { + Double_t Ephoton = aTrack->GetMomentum().mag(); + Double_t ra = G4UniformRand(); + if (ra > GlueXSensitiveDetectorDIRC::GetDetectionEfficiency(Ephoton)) + return fKill; + + G4ThreeVector v = aTrack->GetPosition(); + G4ThreeVector n = aTrack->GetMomentumDirection().unit(); + + Double_t bary = 35; // bar width + Double_t barz = 17.25; // bar height + Double_t barx = 4*1225; // bar length + + Double_t lenx; + if (v.y()<0) { + lenx = fabs(fBarEnd+v.x()); + if (n.x()>0) + lenx = 2*barx - lenx; + } + else { + lenx = fabs(v.x()-fBarEnd); + if (n.x()<0) + lenx = 2*barx - lenx; + } + + Double_t lenz = lenx*n.z()/fabs(n.x()); + Double_t leny = lenx*n.y()/fabs(n.x()); + + int bouncesz = fabs(lenz/barz); + int bouncesy = fabs(leny/bary); + +#ifdef DIRC_MONITORING_HISTOS + hbouncez->Fill(bouncesz); + hbouncey->Fill(bouncesy); +#endif + + Double_t anglez = fabs(n.getTheta()-CLHEP::pi/2.); + Double_t angley = fabs(n.angle(G4ThreeVector(0,1,0))-CLHEP::pi/2.); + + Double_t lambda = 197.0*2.0*CLHEP::pi/(aTrack->GetMomentum().mag()*1.0E6); + Double_t lambda2 = lambda*lambda; + + // calculate bounce probability + Double_t n_quartz = sqrt(1 + (0.696*lambda2/(lambda2-pow(0.068,2))) + (0.407*lambda2/(lambda2-pow(0.116,2))) + 0.897*lambda2/(lambda2-pow(9.896,2))); + Double_t bounce_probz = 1 - pow(4*CLHEP::pi*cos(anglez)*0.5*n_quartz/lambda,2);// 0.5 [nm] - roughness + Double_t bounce_proby = 1 - pow(4*CLHEP::pi*cos(angley)*0.5*n_quartz/lambda,2); + Double_t prob = pow(bounce_probz,bouncesz) * pow(bounce_proby,bouncesy); + + // transport efficiency + if (G4UniformRand() > prob) + return fKill; + } //else {return fKill;} // remove this condition!!! + } // if particle is secondary return fUrgent; } diff --git a/src/GlueXStackingAction.hh b/src/GlueXStackingAction.hh index 2586bef..5e3da41 100644 --- a/src/GlueXStackingAction.hh +++ b/src/GlueXStackingAction.hh @@ -12,6 +12,8 @@ #include "G4UserStackingAction.hh" #include "G4ClassificationOfNewTrack.hh" +#include "TGraph.h" +#include "TRandom.h" class G4StackManager; class G4Track; @@ -29,6 +31,9 @@ class GlueXStackingAction : public G4UserStackingAction protected: int nosecondaries; + + private: + double fBarEnd; }; #endif diff --git a/src/GlueXSteppingAction.cc b/src/GlueXSteppingAction.cc index 36fd01b..6e7e386 100644 --- a/src/GlueXSteppingAction.cc +++ b/src/GlueXSteppingAction.cc @@ -113,7 +113,7 @@ void GlueXSteppingAction::UserSteppingAction(const G4Step* step) if (primeID > 0) { const G4VProcess* process; process = step->GetPostStepPoint()->GetProcessDefinedStep(); - if (dynamic_cast(process)) { + if (process->GetProcessType() == fDecay) { G4TrackVector &secondary = *(G4TrackVector*) step->GetSecondaryInCurrentStep(); G4TrackVector::iterator iter; diff --git a/src/GlueXUserEventInformation.cc b/src/GlueXUserEventInformation.cc index 92acd67..9fcae54 100644 --- a/src/GlueXUserEventInformation.cc +++ b/src/GlueXUserEventInformation.cc @@ -13,6 +13,7 @@ #include "Randomize.hh" int GlueXUserEventInformation::fWriteNoHitEvents = 0; +long int *GlueXUserEventInformation::fStartingSeeds = 0; GlueXUserEventInformation::GlueXUserEventInformation(hddm_s::HDDM *hddmevent) : fKeepEvent(true), @@ -42,7 +43,9 @@ GlueXUserEventInformation::~GlueXUserEventInformation() } if (fKeepEvent) { hddm_s::PhysicsEventList pev = fOutputRecord->getPhysicsEvents(); - pev(0).setRunNo(HddmOutput::getRunNo()); + int runno = HddmOutput::getRunNo(); + if (runno > 0) + pev(0).setRunNo(runno); if (pev(0).getEventNo() == 0) { pev(0).setEventNo(HddmOutput::incrementEventNo()); } @@ -362,8 +365,26 @@ void GlueXUserEventInformation::AddMCtrajectoryPoint(const G4Step &step, } } +void GlueXUserEventInformation::SetStartingSeeds(const long int seeds[2]) +{ + if (fStartingSeeds) + delete [] fStartingSeeds; + fStartingSeeds = new long int[2]; + fStartingSeeds[0] = seeds[0]; + fStartingSeeds[1] = seeds[1]; +} + void GlueXUserEventInformation::SetRandomSeeds() { + // Three sources of the starting random number seed for each + // event are supported, in order of high priority to low: + // 1) the tag in the input hddm file, if any + // 2) seeds set by a recent call to SetStartingSeeds() + // 3) the current internal state of the generator + // In case (2), the starting seeds are used to reset the + // internal state of the randoms generator just once, and + // then never used again. + hddm_s::PhysicsEventList pev = fOutputRecord->getPhysicsEvents(); hddm_s::ReactionList rea = pev(0).getReactions(); if (rea.size() == 0) { @@ -375,8 +396,17 @@ void GlueXUserEventInformation::SetRandomSeeds() seed[0] = rnd(0).getSeed1(); seed[1] = rnd(0).getSeed2(); G4Random::setTheSeeds(seed); +#if VERBOSE_RANDOMS + G4cout << "New event with starting seeds " + << seed[0] << ", " << seed[1] << G4endl; +#endif } else { + if (fStartingSeeds) { + G4Random::setTheSeeds(fStartingSeeds); + delete fStartingSeeds; + fStartingSeeds = 0; + } const long int *seed = G4Random::getTheSeeds(); rnd = rea(0).addRandoms(); rnd(0).setSeed1(seed[0]); @@ -390,6 +420,14 @@ void GlueXUserEventInformation::SetRandomSeeds() } } +int GlueXUserEventInformation::GetRunNo() +{ + if (fOutputRecord && fOutputRecord->getPhysicsEvents().size() > 0) { + return fOutputRecord->getPhysicsEvent().getRunNo(); + } + return 0; +} + double GlueXUserEventInformation::GetBeamPhotonEnergy() { hddm_s::BeamList beam = fOutputRecord->getBeams(); diff --git a/src/GlueXUserEventInformation.hh b/src/GlueXUserEventInformation.hh index 87b2e7f..b9e342f 100644 --- a/src/GlueXUserEventInformation.hh +++ b/src/GlueXUserEventInformation.hh @@ -43,6 +43,7 @@ class GlueXUserEventInformation: public G4VUserEventInformation int parentID, int mech); void AddMCtrajectoryPoint(const G4Step &step, int save_option); + int GetRunNo(); double GetBeamPhotonEnergy(); int GetGlueXTrackID(int g4ID); int GetGlueXTrackID(const G4Track *track); @@ -54,6 +55,7 @@ class GlueXUserEventInformation: public G4VUserEventInformation void SetKeepEvent(int flag) { fKeepEvent = flag; } int GetKeepEvent() const { return fKeepEvent; } + static void SetStartingSeeds(const long int seeds[2]); void SetRandomSeeds(); void Print() const; @@ -62,6 +64,7 @@ class GlueXUserEventInformation: public G4VUserEventInformation } static int fWriteNoHitEvents; + static long int *fStartingSeeds; protected: hddm_s::HDDM *fOutputRecord; diff --git a/src/HddsG4Builder.cc b/src/HddsG4Builder.cc index 22c9c94..1928d23 100644 --- a/src/HddsG4Builder.cc +++ b/src/HddsG4Builder.cc @@ -160,7 +160,7 @@ int HddsG4Builder::createMaterial(DOMElement* el) valS = specEl->getAttribute(X("smooth")); smooth.push_back(atof(S(valS))); valS = specEl->getAttribute(X("reflect")); - reflect.push_back(atof(S(valS)));; + reflect.push_back(atof(S(valS))); valS = specEl->getAttribute(X("effic")); effic.push_back(atof(S(valS))); } @@ -298,7 +298,7 @@ int HddsG4Builder::createSolid(DOMElement* el, Refsys& ref) std::vector rInner; std::vector rOuter; double zlast = -1e30; - double zeps = 1e-5; + double zeps = 0; for (unsigned int p = 0; p < planeList->getLength(); p++) { double ri, ro, zl; @@ -345,7 +345,7 @@ int HddsG4Builder::createSolid(DOMElement* el, Refsys& ref) std::vector rInner; std::vector rOuter; double zlast = -1e30; - double zeps = 1e-5; + double zeps = 0; for (unsigned int p = 0; p < planeList->getLength(); p++) { double ri, ro, zl; @@ -475,6 +475,7 @@ int HddsG4Builder::createSolid(DOMElement* el, Refsys& ref) G4OpticalSurface *surface = new G4OpticalSurface(S(nameS)); surface->SetType(dielectric_metal); surface->SetModel(glisur); + surface->SetMaterialPropertiesTable(mpt); if (poli_vector != 0) { double polish = poli_vector->GetMaxValue(); surface->SetPolish(polish); @@ -491,6 +492,7 @@ int HddsG4Builder::createSolid(DOMElement* el, Refsys& ref) G4OpticalSurface *surface = new G4OpticalSurface(S(nameS)); surface->SetType(dielectric_dielectric); surface->SetModel(glisur); + surface->SetMaterialPropertiesTable(mpt); if (poli_vector != 0) { double polish = poli_vector->GetMaxValue(); surface->SetPolish(polish); diff --git a/src/HddsGeometryXML.hh b/src/HddsGeometryXML.hh new file mode 100644 index 0000000..3569399 --- /dev/null +++ b/src/HddsGeometryXML.hh @@ -0,0 +1,28 @@ +// +// HddsGeometry - class header +// +// author: richard.t.jones at uconn.edu +// version: november 21, 2017 +// +// In the context of the Geant4 event-level multithreading model, +// this class is "shared", ie. has no thread-local state. + +#ifndef _HDDSGEOMETRYXML_ +#define _HDDSGEOMETRYXML_ + +#include + +class HddsGeometryXML : public jana::JGeometryXML +{ + public: + HddsGeometryXML(std::string url, int run) : jana::JGeometryXML(url, run, "") {} + ~HddsGeometryXML() {} + + DOMDocument *getDocument() { return doc; } + + private: + HddsGeometryXML(const HddsGeometryXML &src); + HddsGeometryXML &operator=(const HddsGeometryXML &src); +}; + +#endif diff --git a/src/OpenGLXpreload.cc b/src/OpenGLXpreload.cc new file mode 100644 index 0000000..ab7f9f7 --- /dev/null +++ b/src/OpenGLXpreload.cc @@ -0,0 +1,14 @@ +#include +#include +#include + +static int attributeList[] = { GLX_RGBA, None }; + +void OpenGLXpreload() { + Display *dpy; + XVisualInfo *vi; + /* get a connection */ + dpy = XOpenDisplay(0); + /* get an appropriate visual */ + vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList); +} diff --git a/src/PairConversionGeneration.cc b/src/PairConversionGeneration.cc index 8ab3a06..778acb1 100644 --- a/src/PairConversionGeneration.cc +++ b/src/PairConversionGeneration.cc @@ -62,15 +62,16 @@ PairConversionGeneration::PairConversionGeneration() PairConversionGeneration::~PairConversionGeneration() {} -double PairConversionGeneration::FFatomic(double qRecoil) +LDouble_t PairConversionGeneration::FFatomic(LDouble_t qRecoil) { // return the atomic form factor of the pair converter // normalized to unity at zero momentum transfer qRecoil (GeV/c). + // Lengths are in Angstroms in this function. #if H_DIPOLE_FORM_FACTOR - double a0Bohr = 0.529177 / 1.97327e-6; - double ff = 1 / pow(1 + pow(a0Bohr * qRecoil, 2) / 4, 2); + LDouble_t a0Bohr = 0.529177 / 1.97327e-6; + LDouble_t ff = 1 / pow(1 + pow(a0Bohr * qRecoil, 2), 2); #else @@ -78,6 +79,8 @@ double PairConversionGeneration::FFatomic(double qRecoil) // http://lampx.tugraz.at/~hadley/ss1/crystaldiffraction // /atomicformfactors/formfactors.php + int Z=4; + LDouble_t acoeff[] = {1.5919, 1.1278, 0.5391, 0.7029}; LDouble_t bcoeff[] = {43.6427, 1.8623, 103.483, 0.5420}; LDouble_t ccoeff[] = {0.0385}; @@ -87,16 +90,16 @@ double PairConversionGeneration::FFatomic(double qRecoil) for (int i=0; i < 4; ++i) { ff += acoeff[i] * exp(-bcoeff[i] * pow(q_invA / (4 * M_PI), 2)); } - ff /= 4; + ff /= Z; #endif return ff; } -double PairConversionGeneration::DiffXS_pair(const TPhoton &gIn, - const TLepton &pOut, - const TLepton &eOut) +LDouble_t PairConversionGeneration::DiffXS_pair(const TPhoton &gIn, + const TLepton &pOut, + const TLepton &eOut) { // Calculates the e+e- pair production cross section for a // gamma ray off an atom at a particular recoil momentum vector q. @@ -120,27 +123,26 @@ double PairConversionGeneration::DiffXS_pair(const TPhoton &gIn, e2.AllPol(); // Multiply the basic cross section by the converter atomic form factor - double result = TCrossSection::PairProduction(g0, e2, p1); + LDouble_t result = TCrossSection::PairProduction(g0, e2, p1); TFourVectorReal qR(gIn.Mom() - eOut.Mom() - pOut.Mom()); - double Q2 = fabs(qR.InvariantSqr()); - result *= sqr(fConverterZ * (1 - FFatomic(sqrt(Q2)))); + result *= sqr(fConverterZ * (1 - FFatomic(qR.Length()))); return result * 1e-6; // The unpolarized Bethe-Heitler cross section is given here for comparison - double kin = gIn.Mom()[0]; - double Epos = pOut.Mom()[0]; - double Eele = eOut.Mom()[0]; - double delta = 136 * mElectron / pow(fConverterZ, 0.33333) * - kin / (Eele * Epos); - double aCoul = sqr(alphaQED * fConverterZ); - double fCoul = aCoul * (1 / (1 + aCoul) + 0.20206 - 0.0369 * aCoul + - 0.0083 * pow(aCoul, 2) - 0.002 * pow(aCoul, 3)); - double xsi = log(1440 / pow(fConverterZ, 0.66667)) / - (log(183 / pow(fConverterZ, 0.33333) - fCoul)); - double FofZ = (8./3.) * log(fConverterZ) + ((kin < 0.05)? 0 : 8 * fCoul); - double Phi1 = 20.867 - 3.242 * delta + 0.625 * sqr(delta); - double Phi2 = 20.209 - 1.930 * delta - 0.086 * sqr(delta); - double Phi0 = 21.12 - 4.184 * log(delta + 0.952); + LDouble_t kin = gIn.Mom()[0]; + LDouble_t Epos = pOut.Mom()[0]; + LDouble_t Eele = eOut.Mom()[0]; + LDouble_t delta = 136 * mElectron / pow(fConverterZ, 0.33333) * + kin / (Eele * Epos); + LDouble_t aCoul = sqr(alphaQED * fConverterZ); + LDouble_t fCoul = aCoul * (1 / (1 + aCoul) + 0.20206 - 0.0369 * aCoul + + 0.0083 * pow(aCoul, 2) - 0.002 * pow(aCoul, 3)); + LDouble_t xsi = log(1440 / pow(fConverterZ, 0.66667)) / + (log(183 / pow(fConverterZ, 0.33333) - fCoul)); + LDouble_t FofZ = (8./3.) * log(fConverterZ) + ((kin < 0.05)? 0 : 8 * fCoul); + LDouble_t Phi1 = 20.867 - 3.242 * delta + 0.625 * sqr(delta); + LDouble_t Phi2 = 20.209 - 1.930 * delta - 0.086 * sqr(delta); + LDouble_t Phi0 = 21.12 - 4.184 * log(delta + 0.952); if (delta > 1) { Phi1 = Phi2 = Phi0; } @@ -153,10 +155,10 @@ double PairConversionGeneration::DiffXS_pair(const TPhoton &gIn, return result * 1e-6; } -double PairConversionGeneration::DiffXS_triplet(const TPhoton &gIn, - const TLepton &pOut, - const TLepton &eOut2, - const TLepton &eOut3) +LDouble_t PairConversionGeneration::DiffXS_triplet(const TPhoton &gIn, + const TLepton &pOut, + const TLepton &eOut2, + const TLepton &eOut3) { // Calculates the e+e- pair production rate on a free electron target, // including incident photon polarization effects, for a given set of @@ -164,8 +166,9 @@ double PairConversionGeneration::DiffXS_triplet(const TPhoton &gIn, // energy kin, the mass of the e+e- pair M, the recoil momentum vector // qR, the azimuthal angle of the plane containing the e+e- pair phi+, // and the energy of the pair positron E+. The returned value is the - // differential cross section measured in barns/GeV^4, differential - // in (d^3 qR dphi+ dE+) = (M / 2 kin) (dM dqR^2 dphiR dphi+ dE+). + // differential cross section measured in barns/GeV^4 per atom, with + // fConverterZ electrons per atom, differential in + // (d^3 qR dphi+ dE+) = (M / 2 kin) (dM dqR^2 dphiR dphi+ dE+). TPhoton g0(gIn); TLepton e0(zeroVector, mElectron); @@ -185,10 +188,8 @@ double PairConversionGeneration::DiffXS_triplet(const TPhoton &gIn, e3.AllPol(); // Correct the basic cross section by the converter atomic form factor - double result = TCrossSection::TripletProduction(g0, e0, p1, e2, e3); - TFourVectorReal qR(e3.Mom() - e0.Mom()); - double Q2 = fabs(qR.InvariantSqr()); - result *= fConverterZ * (1 - sqr(FFatomic(sqrt(Q2)))); + LDouble_t result = TCrossSection::TripletProduction(g0, e0, p1, e2, e3); + result *= fConverterZ * (1 - sqr(FFatomic(e3.Mom().Length()))); return result * 1e-6; } diff --git a/src/PairConversionGeneration.hh b/src/PairConversionGeneration.hh index 7fa03c9..cd1d636 100644 --- a/src/PairConversionGeneration.hh +++ b/src/PairConversionGeneration.hh @@ -42,11 +42,11 @@ class PairConversionGeneration { PairConversionGeneration(); ~PairConversionGeneration(); - double FFatomic(double qRecoil); - double DiffXS_pair(const TPhoton &gIn, - const TLepton &pOut, const TLepton &eOut); - double DiffXS_triplet(const TPhoton &gIn, const TLepton &pOut, - const TLepton &eOut2, const TLepton &eOut3); + LDouble_t FFatomic(LDouble_t qRecoil); + LDouble_t DiffXS_pair(const TPhoton &gIn, + const TLepton &pOut, const TLepton &eOut); + LDouble_t DiffXS_triplet(const TPhoton &gIn, const TLepton &pOut, + const TLepton &eOut2, const TLepton &eOut3); const TThreeVectorReal &GetPolarization(); unsigned int GetConverterZ(); diff --git a/src/hdgeant4.cc b/src/hdgeant4.cc index 82217c0..1083899 100644 --- a/src/hdgeant4.cc +++ b/src/hdgeant4.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,8 @@ #include #include #include +#include +#include #ifdef G4VIS_USE #include @@ -46,6 +49,10 @@ void usage() exit(9); } +void OpenGLXpreload(); +void describe(std::string volname, int level=0); +void describe(G4SmartVoxelHeader *vox, std::string mother, int level=0); + int main(int argc,char** argv) { // Initialize the jana framework @@ -72,6 +79,13 @@ int main(int argc,char** argv) } } + // Initialize the graphics subsystem, if requested + if (use_visualization) { +#ifdef G4VIS_USE + OpenGLXpreload(); +#endif + } + // Read user options from file control.in GlueXUserOptions opts; if (! opts.ReadControl_in("control.in")) { @@ -79,14 +93,24 @@ int main(int argc,char** argv) } if (run_number == 0) { std::map runno_opts; + std::map infile_opts; if (opts.Find("RUNNO", runno_opts) || opts.Find("RUNG", runno_opts)) { run_number = runno_opts[1]; } - else { - G4cerr << "Warning - " - << "no run number specified in control.in, " - << "default value of 9000 assumed." << G4endl; - run_number = 9000; + else if (opts.Find("INFILE", infile_opts) || + opts.Find("INFI", infile_opts)) + { + std::ifstream fin(infile_opts[1].c_str()); + if (!fin.is_open()) { + G4cerr << "Input error: Unable to open HDDM input file: " + << infile_opts[1] << G4endl; + exit(-1); + } + hddm_s::istream ifs(fin); + hddm_s::HDDM record; + while (record.getPhysicsEvents().size() == 0) + ifs >> record; + run_number = record.getPhysicsEvents()(0).getRunNo(); } } @@ -116,6 +140,7 @@ int main(int argc,char** argv) G4Random::setTheSeeds(seed); } } + GlueXUserEventInformation::SetStartingSeeds(G4Random::getTheSeeds()); // Declare our G4VSteppingVerbose implementation G4VSteppingVerbose::SetInstance(new GlueXSteppingVerbose()); @@ -127,13 +152,14 @@ int main(int argc,char** argv) #else G4RunManager runManager; #endif + runManager.SetVerboseLevel(0); - // Let user turn off geometry optimization for faster startup - // (and slower running) - std::map geomopt; - if ( opts.Find("GEOMOPT", geomopt) ) { - if( geomopt[1] == 0 ) runManager.SetGeometryToBeOptimized( false ); - } + // Let user turn off geometry optimization for faster startup + // (and slower running) + std::map geomopt; + if ( opts.Find("GEOMOPT", geomopt) ) { + if( geomopt[1] == 0 ) runManager.SetGeometryToBeOptimized( false ); + } // Geometry initialization GlueXDetectorConstruction *geometry = new GlueXDetectorConstruction(); @@ -146,9 +172,21 @@ int main(int argc,char** argv) } runManager.SetUserInitialization(geometry); +#if REDUCE_OPTIMIZATION_OF_CDC + // Save some time at startup by reducing the level + // of optimization of the CDC geometry + G4LogicalVolumeStore *volumes = G4LogicalVolumeStore::GetInstance(); + G4LogicalVolume *logvol = volumes->GetVolume("DCLS"); + if (logvol) { + logvol->SetSmartless(0.5); + } +#endif + // Physics process initialization GlueXPhysicsList *physicslist = new GlueXPhysicsList(); runManager.SetUserInitialization(physicslist); + G4HadronicProcessStore *pstore = G4HadronicProcessStore::Instance(); + pstore->SetVerbose(0); // User actions initialization GlueXUserActionInitialization *userinit; @@ -156,7 +194,10 @@ int main(int argc,char** argv) runManager.SetUserInitialization(userinit); // Initialize G4 kernel + std::cout << "Initializing the Geant4 kernel..." << std::endl; runManager.Initialize(); + + //describe("DCLS"); // Initialize graphics (option -v) G4VisManager* visManager = 0; @@ -265,3 +306,66 @@ int main(int argc,char** argv) GlueXTimer::PrintAll(); return 0; } + +void describe(std::string volname, int level) +{ + G4LogicalVolumeStore *volumes = G4LogicalVolumeStore::GetInstance(); + G4LogicalVolume *logvol = volumes->GetVolume(volname); + int childcount = logvol->GetNoDaughters(); + G4cout << "(" << level << ") " << "logical volume " << volname << ": " + << childcount << " daughters" + << std::endl; + G4SmartVoxelHeader *vox = logvol->GetVoxelHeader(); + if (vox) { + describe(vox, volname); + } + std::map children; + for (int i=0; i < childcount; ++i) { + G4VPhysicalVolume *child = logvol->GetDaughter(i); + std::string name(child->GetLogicalVolume()->GetName()); + if (children.find(name) == children.end()) { + children[name] = 1; + describe(name, level+1); + } + else { + children[name] += 1; + } + } +} + +void describe(G4SmartVoxelHeader *vox, std::string mother, int level) +{ + G4LogicalVolumeStore *volumes = G4LogicalVolumeStore::GetInstance(); + G4LogicalVolume *motherlog = volumes->GetVolume(mother); + int nslices = vox->GetNoSlices(); + for (int l=0; l < level; ++l) + G4cout << " "; + G4cout << " sliced along axis " << vox->GetAxis() + << " into " << nslices << " slices" + << " from " << vox->GetMinExtent() << " to " << vox->GetMaxExtent() + << " (" << vox->GetMinEquivalentSliceNo() << "," + << vox->GetMaxEquivalentSliceNo() << ")" + << std::endl; + for (int s=0; s < nslices; ++s) { + for (int l=0; l < level; ++l) + G4cout << " "; + G4cout << " " << s << ": "; + G4SmartVoxelProxy *prox = vox->GetSlice(s); + if (prox->IsHeader()) { + G4cout << "(holds another level of voxels)" << std::endl; + describe(prox->GetHeader(), mother, level+1); + continue; + } + G4SmartVoxelNode *node = prox->GetNode(); + int ncont = node->GetNoContained(); + G4cout << "node contains " << ncont << " volumes" + << " (" << prox->GetNode()->GetMinEquivalentSliceNo() << "," + << prox->GetNode()->GetMaxEquivalentSliceNo() << ")"; + for (int c=0; c < ncont; c++) { + int ic = node->GetVolume(c); + G4VPhysicalVolume *cvol = motherlog->GetDaughter(ic); + G4cout << " " << cvol->GetName() << "[" << cvol->GetCopyNo() << "]"; + } + G4cout << std::endl; + } +} diff --git a/src/utils/genBH.cc b/src/utils/genBH.cc new file mode 100644 index 0000000..30defe8 --- /dev/null +++ b/src/utils/genBH.cc @@ -0,0 +1,364 @@ +// +// genBH.cc : Bethe Heitler event generator +// +// author: richard.t.jones at uconn.edu +// version: march 15, 2018 +// +// usage: genBH -n <#> [options] +// where options may include any of the following +// -t <#> : number of threads to run, default 1 +// -E : energy of incident photon (GeV), default 9.0 +// -e : use bremsstrahlung spectrum with endpoint e (GeV) +// +// notes: +// 1) If option -e is specified, the value of the E option is taken +// as the minimum photon energy in the generated bremsstrahlung +// spectrum. +// +// 2) The event count option -n <#> must be present, but it does not +// have to be first among options, as shown in the usage pattern. +// +// physics: +// 1) The generator is based on the tree-level e+e- pair production +// process from elastic scattering from a free nucleon. +// 2) A complete treatment of the tree-level cross section is used, +// taking into account polarization of the incident photon and +// nucleon. It also supports polarization selection of the outgoing +// nucleon and leptons. Default behavior is to sum over final spins +// but there is no need to to this if specific polarization in the +// final state particles is of interest. +// 3) The nucleon target structure is represented by the Dirac and +// Pauli form factors. The case of scattering from free electrons +// or coherent scattering from atoms is covered by other tools in +// the Dirac++ package (see Triplets.C, or or Pairs.C). +// 4) The weight factors written into the output hddm tag +// must be carried with the event. They have units of microbarns, +// defined such that the total Bethe Heitler cross section can be +// estimated by Monte Carlo integration as the average value of +// these weights. +// + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +double Ephoton(9.0); +double Endpoint(0.); +std::atomic eventNo(0); + +typename hddm_mc_s::ostream *esink; + +void usage() +{ + std::cout << + "Usage: genBH -n <#> [options] \n" + " where options may include any of the following\n" + " -t <#> : number of threads to run, default 1\n" + " -E : energy of incident photon (GeV), default 9.0\n" + " -e : use bremsstrahlung spectrum with endpoint e (GeV)\n" + << std::endl; + exit(1); +} + +int generate(int nevents) +{ + thread_local TRandom2 *randoms; + randoms = new TRandom2(0); + + double sum(0); + double sum2(0); + for (int n = 0; n < nevents; ++n) { + LDouble_t weight = 1; + LDouble_t kin = Ephoton; + + // generate Epos uniform on [0,kin] + LDouble_t Epos = randoms->Uniform(kin); + weight *= kin; + + // generate phi12 uniform on [0,2pi] + LDouble_t phi12 = randoms->Uniform(2*PI_); + weight *= 2*PI_; + + // generate phiR uniform on [0,2pi] + LDouble_t phiR = randoms->Uniform(2*PI_); + weight *= 2*PI_; + + // generate Mpair with weight (1/M) / (Mcut^2 + M^2) + LDouble_t Mmin = 2 * mElectron; + LDouble_t Mcut = 5e-3; // 5 MeV cutoff parameter + LDouble_t um0 = 1 + sqr(Mcut / Mmin); + LDouble_t um = pow(um0, randoms->Uniform(1)); + LDouble_t Mpair = Mcut / sqrt(um - 1); + weight *= Mpair * (sqr(Mcut) + sqr(Mpair)) + * log(um0) / (2 * sqr(Mcut)); + + // generate qR^2 with weight (1/qR^2) / sqrt(qRcut^2 + qR^2) + LDouble_t qRmin = sqr(Mpair )/ (2 * kin); + LDouble_t qRcut = 1e-3; // 1 MeV/c cutoff parameter + LDouble_t uq0 = qRmin / (qRcut + sqrt(sqr(qRcut) + sqr(qRmin))); + LDouble_t uq = pow(uq0, randoms->Uniform(1)); + LDouble_t qR2 = sqr(2 * qRcut * uq/(1 - sqr(uq))); + weight *= qR2 * sqrt(1 + qR2 / sqr(qRcut)) + * (-2 * log(uq0)); + + // overall measure Jacobian factor + weight *= Mpair / (2 * kin); + + // compute the differential cross section + TPhoton gIn; + TLepton eOut(mElectron), pOut(mElectron); + TLepton nIn(mProton), nOut(mProton); + LDouble_t diffXS(0); + + try { + nIn.SetMom(TThreeVectorReal(0,0,0)); + gIn.SetMom(TThreeVectorReal(0,0,kin)); + + // Solve for the rest of the kinematics + LDouble_t qR = sqrt(qR2); + LDouble_t Erec = sqrt(sqr(mProton) + qR2); + //LDouble_t Eele = kin + mProton - Erec - Epos; + LDouble_t costhetaR = (2 * (mProton + kin) * (Erec - mProton) + + sqr(Mpair)) / (2 * kin * qR); + if (costhetaR > 1) { + throw std::runtime_error("no kinematic solution because costhetaR > 1"); + } + LDouble_t sinthetaR = sqrt(1 - sqr(costhetaR)); + TThreeVectorReal qRecoil(qR * sinthetaR * cos(phiR), + qR * sinthetaR * sin(phiR), + qR * costhetaR); + nOut.SetMom(qRecoil); + + LDouble_t pStar2 = sqr(Mpair / 2) - sqr(mElectron); + if (pStar2 < 0) { + throw std::runtime_error("no kinematic solution because pStar2 < 0"); + } + LDouble_t pStar = sqrt(pStar2); + LDouble_t E12 = kin + mProton - Erec; + LDouble_t p12mag = sqrt(sqr(E12) - sqr(Mpair)); + LDouble_t costhetastar = (Epos - E12 / 2) * Mpair / (pStar * p12mag); + if (fabs(costhetastar) > 1) { + throw std::runtime_error("no kinematic solution because costhetastar < 1"); + } + LDouble_t sinthetastar = sqrt(1 - sqr(costhetastar)); + TThreeVectorReal k12(pStar * sinthetastar * cos(phi12), + pStar * sinthetastar * sin(phi12), + pStar * costhetastar); + TFourVectorReal p1(Mpair / 2, k12); + TLorentzBoost toLab(qRecoil[1] / E12, + qRecoil[2] / E12, + (qRecoil[3] - kin) / E12); + p1.Boost(toLab); + pOut.SetMom(p1); + TThreeVectorReal p2(gIn.Mom() - qRecoil - p1); + eOut.SetMom(p2); + + // Set the initial,final polarizations + gIn.SetPol(TThreeVectorReal(1,0,0)); + nIn.SetPol(TThreeVectorReal(0,0,0)); + eOut.AllPol(); + pOut.AllPol(); + nOut.AllPol(); + + // Compute the polarized differential cross section + LDouble_t F1_spacelike = 1; + LDouble_t F2_spacelike = 0; + LDouble_t F1_timelike = 1; + LDouble_t F2_timelike = 0; + diffXS = TCrossSection::BetheHeitlerNucleon(gIn, nIn, + eOut, pOut, nOut, + F1_spacelike, + F2_spacelike, + F1_timelike, + F2_timelike); + } + catch (const std::exception &e) { + + // These events have no cross section, but do not discard + // them because they are needed to get the right MC integral. + + nOut.SetMom(TThreeVectorReal(0,0,0)); + eOut.SetMom(TThreeVectorReal(0,0,0)); + pOut.SetMom(TThreeVectorReal(0,0,0)); + diffXS = 0; + } + + // Keep statistics on the total cross section + sum += weight * diffXS; + sum2 += sqr(weight * diffXS); + if (n > 0 && n / 10000 * 10000 == n) { + std::cout << "est. total cross section after " + << n << " events : " << sum / n + << " +/- " << sqrt(sum2 - sqr(sum) / n) / n + << " ub" << std::endl; + } + + // Save kinematics to output event record + hddm_mc_s::HDDM record; + hddm_mc_s::PhysicsEventList events = record.addPhysicsEvents(); + events(0).setEventNo(++eventNo); + hddm_mc_s::ReactionList reactions = events(0).addReactions(); + reactions(0).setType(235586); + reactions(0).setWeight(weight * diffXS); + hddm_mc_s::BeamList beams = reactions(0).addBeams(); + hddm_mc_s::MomentumList bmoms = beams(0).addMomenta(); + hddm_mc_s::PropertiesList bprops = beams(0).addPropertiesList(); + beams(0).setType(Gamma); + bmoms(0).setE(kin); + bmoms(0).setPx(0); + bmoms(0).setPy(0); + bmoms(0).setPz(kin); + bprops(0).setCharge(0); + bprops(0).setMass(0); + hddm_mc_s::TargetList targs = reactions(0).addTargets(); + hddm_mc_s::MomentumList tmoms = targs(0).addMomenta(); + hddm_mc_s::PropertiesList tprops = targs(0).addPropertiesList(); + targs(0).setType(Proton); + tmoms(0).setE(mProton); + tmoms(0).setPx(0); + tmoms(0).setPy(0); + tmoms(0).setPz(0); + tprops(0).setCharge(1); + tprops(0).setMass(mProton); + hddm_mc_s::VertexList verts = reactions(0).addVertices(); + hddm_mc_s::ProductList prods = verts(0).addProducts(3); + prods(0).setDecayVertex(0); + prods(0).setId(1); + prods(0).setMech(0); + prods(0).setParentid(0); + prods(0).setPdgtype(-11); + prods(0).setType(Positron); + prods(0).setDecayVertex(0); + prods(1).setId(2); + prods(1).setMech(0); + prods(1).setParentid(0); + prods(1).setPdgtype(11); + prods(1).setType(Electron); + prods(1).setDecayVertex(0); + prods(2).setId(3); + prods(2).setMech(0); + prods(2).setParentid(0); + prods(2).setPdgtype(2212); + prods(2).setType(Proton); + for (int i=0; i < 3; ++i) { + prods(i).addMomenta(); + prods(i).addPropertiesList(); + } + prods(0).getMomentum().setE(pOut.Mom()[0]); + prods(0).getMomentum().setPx(pOut.Mom()[1]); + prods(0).getMomentum().setPy(pOut.Mom()[2]); + prods(0).getMomentum().setPz(pOut.Mom()[3]); + prods(0).getProperties().setMass(mElectron); + prods(0).getProperties().setCharge(1); + prods(1).getMomentum().setE(eOut.Mom()[0]); + prods(1).getMomentum().setPx(eOut.Mom()[1]); + prods(1).getMomentum().setPy(eOut.Mom()[2]); + prods(1).getMomentum().setPz(eOut.Mom()[3]); + prods(1).getProperties().setMass(mElectron); + prods(1).getProperties().setCharge(-1); + prods(2).getMomentum().setE(nOut.Mom()[0]); + prods(2).getMomentum().setPx(nOut.Mom()[1]); + prods(2).getMomentum().setPy(nOut.Mom()[2]); + prods(2).getMomentum().setPz(nOut.Mom()[3]); + prods(2).getProperties().setMass(mProton); + prods(2).getProperties().setCharge(+1); + verts(0).addOrigins(); + verts(0).getOrigin().setT(0); + verts(0).getOrigin().setVx(0); + verts(0).getOrigin().setVy(0); + verts(0).getOrigin().setVz(0); + *esink << record; + } + + std::cout << "est. total cross section after " + << nevents << " events : " << sum / nevents + << " +/- " << sqrt(sum2 - sqr(sum) / nevents) / nevents + << " ub" << std::endl; + + delete randoms; + return 0; +} + +int main(int argc, char *argv[]) +{ + int nevents(0); + int nthreads(1); + + std::string outfname; + for (int iarg=1; iarg < argc; ++iarg) { + const char *arg(argv[iarg]); + if (arg[0] != '-') { + outfname.assign(arg); + break; + } + else if (arg[1] == 'n') { + if (strlen(arg) > 2) + nevents = std::atoi(arg+2); + else + nevents = atoi(argv[++iarg]); + } + else if (arg[1] == 't') { + if (strlen(arg) > 2) + nthreads = std::atoi(arg+2); + else + nthreads = atoi(argv[++iarg]); + } + else if (arg[1] == 'E') { + if (strlen(arg) > 2) + Ephoton = std::atof(arg+2); + else + Ephoton = atof(argv[++iarg]); + } + else if (arg[1] == 'e') { + if (strlen(arg) > 2) + Endpoint = std::atof(arg+2); + else + Endpoint = atof(argv[++iarg]); + } + else { + usage(); + } + } + if (nevents == 0 || outfname.size() == 0) + usage(); + + std::ofstream fout(outfname); + if (!fout.is_open()) { + std::cerr << "genBH error - cannot open " + << outfname << " for output, giving up." + << std::endl; + exit(2); + } + esink = new hddm_mc_s::ostream(fout); + + int nevents_per_thread = nevents / nthreads; + if (nevents_per_thread * nthreads < nevents) + nevents_per_thread += 1; + std::vector threads; + for (int n=0; n < nevents;) { + int ni(nevents_per_thread); + ni = (ni > nevents - n)? nevents - n : ni; + threads.push_back(std::thread(generate,ni)); + n += ni; + } + + for (int i=0; i < (int)threads.size(); ++i) { + threads[i].join(); + } +} diff --git a/test/control.in b/test/control.in index bb73966..a2336e3 100644 --- a/test/control.in +++ b/test/control.in @@ -18,9 +18,31 @@ c instructs HDGeant to open ./phi-1680.hddm, skip the first 25 events and then c process the following 100 input events and stop. If the end of the file is c reached before the event count specified in card TRIG is exhausted then the c processing will stop at the end of file. -INFILE 'bggen.hddm' +cINFILE 'bggen.hddm' TRIG 1000000 -RUNG 9001 + +c The RUNG card is one of the ways to set the run number that is written to +c the output events. The simulation run number determines which geometry and +c magnetic field settings are used in the simulation, and also a variety of +c detector readout and digitization parameters that are read from ccdb. +c The simulation run number is selected according to the following rules: +c 1) if it is specified on the command line with the -r option +c then this overrides all other sources; +c 2) if is it specified in this control.in file on a line starting with the +c letters runno or RUNNO then the second field in that line is interpreted +c as an unsigned integer and assigned as the simulation run number; +c 3) if there is no RUNNO line in control.in but there is a line starting +c with rung or RUNG then the second field on the RUNG line is taken +c as the simulation run number and written to the output events; +c 4) if there is no RUNNO or RUNG card in control.in but there is an +c external input event file specified by a line starting with INFI[le] +c then the run number that is written in the input events in that input +c file is carried over to the simulation output events, and used by the +c simulation; +c 5) if none of the above conditions is met then the simulation run number +c is taken to be zero. Normally this is not considered valid, and a +c warning message is printed at startup. +RUNG 51500 c The BEAM card configures the built-in coherent bremsstralung photon c beam generator in HDGeant. If the INFILE card is not present and BEAM @@ -30,7 +52,7 @@ c event source is the external Monte Carlo generator that produced the file, c but the BEAM card may still be present, and it is needed if beam-related c backgrounds are being superimposed on top of the primary event signals, c as requested with the BGRATE card (see below). The beam card accepts -c the following five parameters. +c the following parameters. c Emax - end-point energy of the electron beam (GeV) c Epeak - energy of the primary coherent peak edge (GeV) c Emin - minimum energy of the coherent bremsstrahlung beam (GeV) @@ -38,8 +60,12 @@ c collz - z position of collimator in m c colld - diameter of collimator in m c Eemit - electron beam emittance in m.rad c radthick - dimaond radiator thickneess in m +c spotRMS - virtual spot rms size at the collimator (m) +c spotX - x offset of virtual spot from collimator axis (m) +c spotY - y offset of virtual spot from collimator axis (m) c Omitting the final parameter Emin results in the default value being used. -BEAM 12. 9.0 0.0012 76.00 0.005 10.e-9 20.e-6 +c Setting Epeak to zero selects an amorphous radiator instead of diamond. +cBEAM 12. 9.0 0.0012 76.00 0.005 10.e-9 20.e-6 1e-3 -0.0 +0.0 c The GENBEAM card configures the simulation program to act purely as a c Monte Carlo event generator, and not to actually track any of the particles @@ -119,7 +145,7 @@ c PLOG 1 c TLOG 1 c c particle momentum theta phi delta_momentum delta_theta delta_phi -KINE 108 0.5 90. 180. 0. 180. 360. +KINE 108 0.5 90. 180. 0. 0. 0. c The SCAP card determines the vertex position for the particle gun. It c supports the following three arguments, all of which default to 0. @@ -138,7 +164,7 @@ c by SCAP. Note that this only affects the particle gun. Events read c from a file contain their own vertex information. c c vertex_extent_r vertex_extent_z -TGTWIDTH 0.5 15 +TGTWIDTH 0.5 29.5 c If you specify a non-zero value for vertex_x and/or vertex_y above then c all tracks will emerge from the given point. If you leave them at zero, @@ -181,8 +207,8 @@ c below, and remove any characters before the BGRATE keyword. You are c now ready to go. If you ever change anything in the beamline geometry c eg. the collimator diameter, the coherent edge position, or the value c of beamEmin, do not forget to come back and change your BGRATE. -BGGATE -200. 200. -BGRATE 4.80 +cBGGATE -200. 200. +cBGRATE 2.67 c The above cards BGRATE, BGGATE normally cause the simulation to add c accidental tagger hits to the simulated output record, in addition to @@ -252,7 +278,7 @@ c - tofmax = Time of flight cut (1.E+10 sec) c - gcuts = 5 user words (0.) c Only the first 5 fields (the ones that start with 'cut') c are supported by hdgeant4. -CUTS 1e-4 1e-4 1e-3 1e-3 1e-4 +cCUTS 1e-4 1e-4 1e-3 1e-3 1e-4 c Geant4 introduced the concept of ?a unique cut in range? which allows the user c to specify the threshold for secondaries production in terms of the range that @@ -387,7 +413,7 @@ c similarly named configuration parameters used in the reconstruction, c the difference being that underscores are not allowed here. To c specify the values to the reconstruction code used here, use the c -PBFIELD_TYPE=CalibDB and -PBFIELD_MAP=Magnets/Solenoid/solenoid_1500 -BFIELDMAP 'Magnets/Solenoid/solenoid_1200A_poisson_20140520' +cBFIELDMAP 'Magnets/Solenoid/solenoid_1200A_poisson_20140520' cBFIELDTYPE 'NoField' c The pair spectrometer magnetic field map can also be accessed through the @@ -398,7 +424,7 @@ c supported values for PSBFIELDTYPE. To specify the values used here to c the reconstruction code, use options -PPSBFIELD_TYPE=CalibDB and c -PPSBFIELD_MAP=Magnets/PairSpectrometer/PS_1.8T_20150513_test c on the jana command line. -PSBFIELDMAP 'Magnets/PairSpectrometer/PS_1.8T_20150513_test' +cPSBFIELDMAP 'Magnets/PairSpectrometer/PS_1.8T_20150513_test' cPSBFIELDTYPE 'Const' c Use this card to enable/disable ( SAVEHITS 1/0 ) writing events with no