mirror of
https://github.com/gwm17/SabreRecon.git
synced 2024-11-22 10:18:50 -05:00
First commit
This commit is contained in:
commit
3e4074051c
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
*.o
|
||||
*.so
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
*.cxx
|
||||
*.pcm
|
||||
SabreRecon
|
||||
|
||||
!.gitignore
|
140
CalDict.make
Normal file
140
CalDict.make
Normal file
|
@ -0,0 +1,140 @@
|
|||
# Alternative GNU Make project makefile autogenerated by Premake
|
||||
|
||||
ifndef config
|
||||
config=release
|
||||
endif
|
||||
|
||||
ifndef verbose
|
||||
SILENT = @
|
||||
endif
|
||||
|
||||
.PHONY: clean prebuild
|
||||
|
||||
SHELLTYPE := posix
|
||||
ifeq (.exe,$(findstring .exe,$(ComSpec)))
|
||||
SHELLTYPE := msdos
|
||||
endif
|
||||
|
||||
# Configurations
|
||||
# #############################################
|
||||
|
||||
RESCOMP = windres
|
||||
TARGETDIR = lib
|
||||
TARGET = $(TARGETDIR)/libCalDict.so
|
||||
DEFINES +=
|
||||
INCLUDES += -I. -Isrc/CalDict -isystem /usr/include/root
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lGui -lCore -lImt -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lROOTDataFrame -lROOTVecOps -lTree -lTreePlayer -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lMultiProc -lm -ldl
|
||||
LDDEPS +=
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
@echo Running prebuild commands
|
||||
rootcint -f src/CalDict/cal_dict.cxx src/CalDict/DataStructs.h src/CalDict/LinkDef_CalDict.h
|
||||
cp -rf src/CalDict/*.pcm lib
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
@echo Running postbuild commands
|
||||
cp -rf src/CalDict/DataStructs.h include
|
||||
endef
|
||||
|
||||
ifeq ($(config),release)
|
||||
OBJDIR = objs/Release/CalDict
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -fPIC
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -fPIC -std=c++11
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64/root -L/usr/lib64 -m64 -shared -Wl,-soname=libCalDict.so -s -pthread -rdynamic
|
||||
|
||||
else ifeq ($(config),debug)
|
||||
OBJDIR = objs/Debug/CalDict
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -fPIC -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -fPIC -g -std=c++11
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64/root -L/usr/lib64 -m64 -shared -Wl,-soname=libCalDict.so -pthread -rdynamic
|
||||
|
||||
endif
|
||||
|
||||
# Per File Configurations
|
||||
# #############################################
|
||||
|
||||
|
||||
# File sets
|
||||
# #############################################
|
||||
|
||||
GENERATED :=
|
||||
OBJECTS :=
|
||||
|
||||
GENERATED += $(OBJDIR)/DataStructs.o
|
||||
OBJECTS += $(OBJDIR)/DataStructs.o
|
||||
|
||||
# Rules
|
||||
# #############################################
|
||||
|
||||
all: $(TARGET)
|
||||
@:
|
||||
|
||||
$(TARGET): $(GENERATED) $(OBJECTS) $(LDDEPS) | $(TARGETDIR)
|
||||
$(PRELINKCMDS)
|
||||
@echo Linking CalDict
|
||||
$(SILENT) $(LINKCMD)
|
||||
$(POSTBUILDCMDS)
|
||||
|
||||
$(TARGETDIR):
|
||||
@echo Creating $(TARGETDIR)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(TARGETDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(TARGETDIR))
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
@echo Creating $(OBJDIR)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
|
||||
clean:
|
||||
@echo Cleaning CalDict
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) rm -f $(TARGET)
|
||||
$(SILENT) rm -rf $(GENERATED)
|
||||
$(SILENT) rm -rf $(OBJDIR)
|
||||
else
|
||||
$(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET))
|
||||
$(SILENT) if exist $(subst /,\\,$(GENERATED)) rmdir /s /q $(subst /,\\,$(GENERATED))
|
||||
$(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
|
||||
prebuild: | $(OBJDIR)
|
||||
$(PREBUILDCMDS)
|
||||
|
||||
ifneq (,$(PCH))
|
||||
$(OBJECTS): $(GCH) | $(PCH_PLACEHOLDER)
|
||||
$(GCH): $(PCH) | prebuild
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<"
|
||||
$(PCH_PLACEHOLDER): $(GCH) | $(OBJDIR)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) touch "$@"
|
||||
else
|
||||
$(SILENT) echo $null >> "$@"
|
||||
endif
|
||||
else
|
||||
$(OBJECTS): | prebuild
|
||||
endif
|
||||
|
||||
|
||||
# File Rules
|
||||
# #############################################
|
||||
|
||||
$(OBJDIR)/DataStructs.o: src/CalDict/DataStructs.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
|
||||
-include $(OBJECTS:%.o=%.d)
|
||||
ifneq (,$(PCH))
|
||||
-include $(PCH_PLACEHOLDER).d
|
||||
endif
|
58
Makefile
Normal file
58
Makefile
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Alternative GNU Make workspace makefile autogenerated by Premake
|
||||
|
||||
ifndef config
|
||||
config=release
|
||||
endif
|
||||
|
||||
ifndef verbose
|
||||
SILENT = @
|
||||
endif
|
||||
|
||||
ifeq ($(config),release)
|
||||
CalDict_config = release
|
||||
SabreRecon_config = release
|
||||
|
||||
else ifeq ($(config),debug)
|
||||
CalDict_config = debug
|
||||
SabreRecon_config = debug
|
||||
|
||||
else
|
||||
$(error "invalid configuration $(config)")
|
||||
endif
|
||||
|
||||
PROJECTS := CalDict SabreRecon
|
||||
|
||||
.PHONY: all clean help $(PROJECTS)
|
||||
|
||||
all: $(PROJECTS)
|
||||
|
||||
CalDict:
|
||||
ifneq (,$(CalDict_config))
|
||||
@echo "==== Building CalDict ($(CalDict_config)) ===="
|
||||
@${MAKE} --no-print-directory -C . -f CalDict.make config=$(CalDict_config)
|
||||
endif
|
||||
|
||||
SabreRecon: CalDict
|
||||
ifneq (,$(SabreRecon_config))
|
||||
@echo "==== Building SabreRecon ($(SabreRecon_config)) ===="
|
||||
@${MAKE} --no-print-directory -C . -f SabreRecon.make config=$(SabreRecon_config)
|
||||
endif
|
||||
|
||||
clean:
|
||||
@${MAKE} --no-print-directory -C . -f CalDict.make clean
|
||||
@${MAKE} --no-print-directory -C . -f SabreRecon.make clean
|
||||
|
||||
help:
|
||||
@echo "Usage: make [config=name] [target]"
|
||||
@echo ""
|
||||
@echo "CONFIGURATIONS:"
|
||||
@echo " release"
|
||||
@echo " debug"
|
||||
@echo ""
|
||||
@echo "TARGETS:"
|
||||
@echo " all (default)"
|
||||
@echo " clean"
|
||||
@echo " CalDict"
|
||||
@echo " SabreRecon"
|
||||
@echo ""
|
||||
@echo "For more information, see https://github.com/premake/premake-core/wiki"
|
180
SabreRecon.make
Normal file
180
SabreRecon.make
Normal file
|
@ -0,0 +1,180 @@
|
|||
# Alternative GNU Make project makefile autogenerated by Premake
|
||||
|
||||
ifndef config
|
||||
config=release
|
||||
endif
|
||||
|
||||
ifndef verbose
|
||||
SILENT = @
|
||||
endif
|
||||
|
||||
.PHONY: clean prebuild
|
||||
|
||||
SHELLTYPE := posix
|
||||
ifeq (.exe,$(findstring .exe,$(ComSpec)))
|
||||
SHELLTYPE := msdos
|
||||
endif
|
||||
|
||||
# Configurations
|
||||
# #############################################
|
||||
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin
|
||||
TARGET = $(TARGETDIR)/SabreRecon
|
||||
DEFINES +=
|
||||
INCLUDES += -Isrc -Isrc/CalDict -Isrc/Detectors -Isrc/EnergyLoss -isystem /usr/include/root
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += lib/libCalDict.so -lGui -lCore -lImt -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lROOTDataFrame -lROOTVecOps -lTree -lTreePlayer -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lMultiProc -lm -ldl
|
||||
LDDEPS += lib/libCalDict.so
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
|
||||
ifeq ($(config),release)
|
||||
OBJDIR = objs/Release/SabreRecon
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -O2
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -std=c++11
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64/root -L/usr/lib64 -Wl,-rpath,'$$ORIGIN/../lib' -m64 -s -pthread -rdynamic
|
||||
|
||||
else ifeq ($(config),debug)
|
||||
OBJDIR = objs/Debug/SabreRecon
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -g -std=c++11
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64/root -L/usr/lib64 -Wl,-rpath,'$$ORIGIN/../lib' -m64 -pthread -rdynamic
|
||||
|
||||
endif
|
||||
|
||||
# Per File Configurations
|
||||
# #############################################
|
||||
|
||||
|
||||
# File sets
|
||||
# #############################################
|
||||
|
||||
GENERATED :=
|
||||
OBJECTS :=
|
||||
|
||||
GENERATED += $(OBJDIR)/CutHandler.o
|
||||
GENERATED += $(OBJDIR)/EnergyLoss.o
|
||||
GENERATED += $(OBJDIR)/FocalPlaneDetector.o
|
||||
GENERATED += $(OBJDIR)/Histogrammer.o
|
||||
GENERATED += $(OBJDIR)/MassLookup.o
|
||||
GENERATED += $(OBJDIR)/RandomGenerator.o
|
||||
GENERATED += $(OBJDIR)/Reconstructor.o
|
||||
GENERATED += $(OBJDIR)/SabreDetector.o
|
||||
GENERATED += $(OBJDIR)/Target.o
|
||||
GENERATED += $(OBJDIR)/main.o
|
||||
OBJECTS += $(OBJDIR)/CutHandler.o
|
||||
OBJECTS += $(OBJDIR)/EnergyLoss.o
|
||||
OBJECTS += $(OBJDIR)/FocalPlaneDetector.o
|
||||
OBJECTS += $(OBJDIR)/Histogrammer.o
|
||||
OBJECTS += $(OBJDIR)/MassLookup.o
|
||||
OBJECTS += $(OBJDIR)/RandomGenerator.o
|
||||
OBJECTS += $(OBJDIR)/Reconstructor.o
|
||||
OBJECTS += $(OBJDIR)/SabreDetector.o
|
||||
OBJECTS += $(OBJDIR)/Target.o
|
||||
OBJECTS += $(OBJDIR)/main.o
|
||||
|
||||
# Rules
|
||||
# #############################################
|
||||
|
||||
all: $(TARGET)
|
||||
@:
|
||||
|
||||
$(TARGET): $(GENERATED) $(OBJECTS) $(LDDEPS) | $(TARGETDIR)
|
||||
$(PRELINKCMDS)
|
||||
@echo Linking SabreRecon
|
||||
$(SILENT) $(LINKCMD)
|
||||
$(POSTBUILDCMDS)
|
||||
|
||||
$(TARGETDIR):
|
||||
@echo Creating $(TARGETDIR)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(TARGETDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(TARGETDIR))
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
@echo Creating $(OBJDIR)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
|
||||
clean:
|
||||
@echo Cleaning SabreRecon
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) rm -f $(TARGET)
|
||||
$(SILENT) rm -rf $(GENERATED)
|
||||
$(SILENT) rm -rf $(OBJDIR)
|
||||
else
|
||||
$(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET))
|
||||
$(SILENT) if exist $(subst /,\\,$(GENERATED)) rmdir /s /q $(subst /,\\,$(GENERATED))
|
||||
$(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
|
||||
prebuild: | $(OBJDIR)
|
||||
$(PREBUILDCMDS)
|
||||
|
||||
ifneq (,$(PCH))
|
||||
$(OBJECTS): $(GCH) | $(PCH_PLACEHOLDER)
|
||||
$(GCH): $(PCH) | prebuild
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<"
|
||||
$(PCH_PLACEHOLDER): $(GCH) | $(OBJDIR)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) touch "$@"
|
||||
else
|
||||
$(SILENT) echo $null >> "$@"
|
||||
endif
|
||||
else
|
||||
$(OBJECTS): | prebuild
|
||||
endif
|
||||
|
||||
|
||||
# File Rules
|
||||
# #############################################
|
||||
|
||||
$(OBJDIR)/CutHandler.o: src/CutHandler.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/FocalPlaneDetector.o: src/Detectors/FocalPlaneDetector.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/SabreDetector.o: src/Detectors/SabreDetector.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/EnergyLoss.o: src/EnergyLoss/EnergyLoss.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/Target.o: src/EnergyLoss/Target.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/Histogrammer.o: src/Histogrammer.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/MassLookup.o: src/MassLookup.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/RandomGenerator.o: src/RandomGenerator.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/Reconstructor.o: src/Reconstructor.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/main.o: src/main.cpp
|
||||
@echo $(notdir $<)
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
|
||||
-include $(OBJECTS:%.o=%.d)
|
||||
ifneq (,$(PCH))
|
||||
-include $(PCH_PLACEHOLDER).d
|
||||
endif
|
2501
etc/mass.txt
Normal file
2501
etc/mass.txt
Normal file
File diff suppressed because it is too large
Load Diff
26
include/DataStructs.h
Normal file
26
include/DataStructs.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef DATA_STRUCTS_H
|
||||
#define DATA_STRUCTS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct SabrePair
|
||||
{
|
||||
int ringch, wedgech; //global
|
||||
int detID;
|
||||
int local_ring, local_wedge; //local (obv.)
|
||||
double ringE, wedgeE;
|
||||
double ringT, wedgeT;
|
||||
};
|
||||
|
||||
struct CalEvent
|
||||
{
|
||||
double xavg = -1e6, x1 = -1e6, x2 = -1e6;
|
||||
double theta = -1, cathodeE = -1, scintE = -1;
|
||||
double anodeFrontE = -1, anodeBackE = -1;
|
||||
double scintT = -1;
|
||||
std::vector<SabrePair> sabre;
|
||||
};
|
||||
|
||||
bool EnforceDictionaryLinked();
|
||||
|
||||
#endif
|
23
input.txt
Normal file
23
input.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
begin_data
|
||||
input /data1/gwm17/10B3He/May2022/calibrated/runs_53_89.root
|
||||
output /data1/gwm17/10B3He/May2022/histograms/calHistograms_53_89_newRecon.root
|
||||
end_data
|
||||
begin_reconstructor
|
||||
begin_focalplane
|
||||
B 8.759
|
||||
theta 15.0
|
||||
begin_fpcal
|
||||
78.5352
|
||||
0.038
|
||||
end_fpcal
|
||||
end_focalplane
|
||||
begin_target
|
||||
thickness 74.0
|
||||
begin_elements
|
||||
5 1
|
||||
end_elements
|
||||
end_target
|
||||
end_reconstructor
|
||||
begin_cuts
|
||||
ede_alphas /data1/gwm17/10B3He/May2022/cuts/edeAlphas.root scintE cathodeE
|
||||
end_cuts
|
4
objs/Release/CalDict/DataStructs.d
Normal file
4
objs/Release/CalDict/DataStructs.d
Normal file
|
@ -0,0 +1,4 @@
|
|||
objs/Release/CalDict/DataStructs.o: src/CalDict/DataStructs.cpp \
|
||||
src/CalDict/DataStructs.h
|
||||
|
||||
src/CalDict/DataStructs.h:
|
114
premake5.lua
Normal file
114
premake5.lua
Normal file
|
@ -0,0 +1,114 @@
|
|||
workspace "SabreRecon"
|
||||
architecture "x64"
|
||||
configurations {
|
||||
"Release",
|
||||
"Debug"
|
||||
}
|
||||
|
||||
ROOTIncludeDir = "/usr/include/root/"
|
||||
ROOTLibDir = "/usr/lib64/root/"
|
||||
|
||||
project "CalDict"
|
||||
kind "SharedLib"
|
||||
language "C++"
|
||||
cppdialect "c++11"
|
||||
targetdir "./lib/"
|
||||
objdir "./objs/"
|
||||
|
||||
prebuildcommands {
|
||||
"rootcint -f src/CalDict/cal_dict.cxx src/CalDict/DataStructs.h src/CalDict/LinkDef_CalDict.h",
|
||||
"{COPY} src/CalDict/*.pcm ./lib/"
|
||||
}
|
||||
|
||||
postbuildcommands {
|
||||
"{COPY} src/CalDict/DataStructs.h ./include/"
|
||||
}
|
||||
|
||||
files {
|
||||
"src/CalDict/DataStructs.h",
|
||||
"src/CalDict/*.cpp",
|
||||
"src/CalDict/*.cxx"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./",
|
||||
"src/CalDict",
|
||||
}
|
||||
|
||||
sysincludedirs {
|
||||
ROOTIncludeDir
|
||||
}
|
||||
|
||||
libdirs {
|
||||
ROOTLibDir
|
||||
}
|
||||
|
||||
links {
|
||||
"Gui", "Core", "Imt", "RIO", "Net", "Hist",
|
||||
"Graf", "Graf3d", "Gpad", "ROOTDataFrame", "ROOTVecOps",
|
||||
"Tree", "TreePlayer", "Rint", "Postscript", "Matrix",
|
||||
"Physics", "MathCore", "Thread", "MultiProc", "m", "dl"
|
||||
}
|
||||
|
||||
filter "system:macosx or linux"
|
||||
linkoptions {
|
||||
"-pthread",
|
||||
"-rdynamic"
|
||||
}
|
||||
|
||||
filter "configurations:Debug"
|
||||
symbols "On"
|
||||
|
||||
filter "configurations:Release"
|
||||
optimize "On"
|
||||
|
||||
project "SabreRecon"
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
cppdialect "c++11"
|
||||
targetdir "./bin/"
|
||||
objdir "./objs/"
|
||||
|
||||
files {
|
||||
"src/*.cpp",
|
||||
"src/*.h",
|
||||
"src/Detectors/*.cpp",
|
||||
"src/Detectors/*.h",
|
||||
"src/EnergyLoss/*.cpp",
|
||||
"src/EnergyLoss/*.h",
|
||||
"src/CalDict/*.h"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"src/",
|
||||
"src/CalDict",
|
||||
"src/Detectors",
|
||||
"src/EnergyLoss"
|
||||
}
|
||||
|
||||
sysincludedirs {
|
||||
ROOTIncludeDir
|
||||
}
|
||||
|
||||
libdirs {
|
||||
ROOTLibDir,
|
||||
}
|
||||
|
||||
links {
|
||||
"CalDict", "Gui", "Core", "Imt", "RIO", "Net", "Hist",
|
||||
"Graf", "Graf3d", "Gpad", "ROOTDataFrame", "ROOTVecOps",
|
||||
"Tree", "TreePlayer", "Rint", "Postscript", "Matrix",
|
||||
"Physics", "MathCore", "Thread", "MultiProc", "m", "dl"
|
||||
}
|
||||
|
||||
filter "system:macosx or linux"
|
||||
linkoptions {
|
||||
"-pthread",
|
||||
"-rdynamic"
|
||||
}
|
||||
|
||||
filter "configurations:Debug"
|
||||
symbols "On"
|
||||
|
||||
filter "configurations:Release"
|
||||
optimize "On"
|
3
src/CalDict/DataStructs.cpp
Normal file
3
src/CalDict/DataStructs.cpp
Normal file
|
@ -0,0 +1,3 @@
|
|||
#include "DataStructs.h"
|
||||
|
||||
bool EnforceDictionaryLinked() { return true; }
|
26
src/CalDict/DataStructs.h
Normal file
26
src/CalDict/DataStructs.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef DATA_STRUCTS_H
|
||||
#define DATA_STRUCTS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct SabrePair
|
||||
{
|
||||
int ringch, wedgech; //global
|
||||
int detID;
|
||||
int local_ring, local_wedge; //local (obv.)
|
||||
double ringE, wedgeE;
|
||||
double ringT, wedgeT;
|
||||
};
|
||||
|
||||
struct CalEvent
|
||||
{
|
||||
double xavg = -1e6, x1 = -1e6, x2 = -1e6;
|
||||
double theta = -1, cathodeE = -1, scintE = -1;
|
||||
double anodeFrontE = -1, anodeBackE = -1;
|
||||
double scintT = -1;
|
||||
std::vector<SabrePair> sabre;
|
||||
};
|
||||
|
||||
bool EnforceDictionaryLinked();
|
||||
|
||||
#endif
|
6
src/CalDict/LinkDef_CalDict.h
Normal file
6
src/CalDict/LinkDef_CalDict.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifdef __ROOTCLING__
|
||||
|
||||
#pragma link C++ struct SabrePair+;
|
||||
#pragma link C++ struct CalEvent+;
|
||||
|
||||
#endif
|
103
src/CutHandler.cpp
Normal file
103
src/CutHandler.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include "CutHandler.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
CutHandler::CutHandler() :
|
||||
m_eventPtr(nullptr), m_isValid(false), m_eventInit(false), m_cutInit(false)
|
||||
{
|
||||
}
|
||||
|
||||
CutHandler::CutHandler(const std::vector<ReconCut>& cuts, CalEvent* event) :
|
||||
m_eventPtr(nullptr), m_isValid(false), m_eventInit(false), m_cutInit(false)
|
||||
{
|
||||
InitCuts(cuts);
|
||||
InitEvent(event);
|
||||
}
|
||||
|
||||
CutHandler::~CutHandler()
|
||||
{
|
||||
for(auto& cut : m_cuts)
|
||||
{
|
||||
if(cut.file_ptr->IsOpen())
|
||||
cut.file_ptr->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void CutHandler::InitCuts(const std::vector<ReconCut>& cuts)
|
||||
{
|
||||
m_cuts = cuts;
|
||||
|
||||
for(auto& cut : m_cuts)
|
||||
{
|
||||
cut.file_ptr = TFile::Open(cut.filename.c_str(), "READ");
|
||||
if(!cut.file_ptr->IsOpen())
|
||||
{
|
||||
std::cerr<<"Unable to open cutfile "<<cut.filename<<std::endl;
|
||||
m_cutInit = false;
|
||||
m_isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
cut.cut_ptr = (TCutG*) cut.file_ptr->Get("CUTG");
|
||||
if(cut.cut_ptr == nullptr)
|
||||
{
|
||||
std::cerr<<"Unable to get CUTG from cutfile "<<cut.filename<<std::endl;
|
||||
m_cutInit = false;
|
||||
m_isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
cut.cut_ptr->SetName(cut.cutname.c_str());
|
||||
}
|
||||
|
||||
m_cutInit = true;
|
||||
if(m_eventInit)
|
||||
m_isValid = true;
|
||||
}
|
||||
|
||||
void CutHandler::InitEvent(CalEvent* event)
|
||||
{
|
||||
m_eventPtr = event;
|
||||
|
||||
if(m_eventPtr == nullptr)
|
||||
{
|
||||
std::cerr<<"Invalid event pointer given to CutHandler::InitEvent!"<<std::endl;
|
||||
m_eventInit = false;
|
||||
m_isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_varMap["xavg"] = &m_eventPtr->xavg;
|
||||
m_varMap["x1"] = &m_eventPtr->x1;
|
||||
m_varMap["x2"] = &m_eventPtr->x2;
|
||||
m_varMap["scintE"] = &m_eventPtr->scintE;
|
||||
m_varMap["cathodeE"] = &m_eventPtr->cathodeE;
|
||||
m_varMap["anodeFrontE"] = &m_eventPtr->anodeFrontE;
|
||||
m_varMap["anodeBackE"] = &m_eventPtr->anodeBackE;
|
||||
m_varMap["theta"] = &m_eventPtr->theta;
|
||||
m_varMap["scintT"] = &m_eventPtr->scintT;
|
||||
|
||||
m_eventInit = true;
|
||||
if(m_cutInit)
|
||||
m_isValid = true;
|
||||
}
|
||||
|
||||
bool CutHandler::IsInside()
|
||||
{
|
||||
for(auto& cut : m_cuts)
|
||||
{
|
||||
auto iterX = m_varMap.find(cut.xparam);
|
||||
auto iterY = m_varMap.find(cut.yparam);
|
||||
if(iterX == m_varMap.end() || iterY == m_varMap.end())
|
||||
{
|
||||
std::cerr<<"Bad variables at CutHandler::IsInside for cut "<<cut.cutname<<" with x: "<<cut.xparam<<" y: "<<cut.yparam<<std::endl;
|
||||
return false;
|
||||
}
|
||||
else if(!cut.cut_ptr->IsInside(*(iterX->second), *(iterY->second)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
54
src/CutHandler.h
Normal file
54
src/CutHandler.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef CUT_HANDLER_H
|
||||
#define CUT_HANDLER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include "TFile.h"
|
||||
#include "TCutG.h"
|
||||
#include "CalDict/DataStructs.h"
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
struct ReconCut
|
||||
{
|
||||
ReconCut() {}
|
||||
ReconCut(const std::string& file, const std::string& cut, const std::string& x, const std::string& y) :
|
||||
xparam(x), yparam(y), filename(file), cutname(cut)
|
||||
{
|
||||
}
|
||||
|
||||
TFile* file_ptr = nullptr;
|
||||
TCutG* cut_ptr = nullptr;
|
||||
std::string xparam = "";
|
||||
std::string yparam = "";
|
||||
std::string filename = "";
|
||||
std::string cutname = "";
|
||||
};
|
||||
|
||||
class CutHandler
|
||||
{
|
||||
public:
|
||||
CutHandler();
|
||||
CutHandler(const std::vector<ReconCut>& cuts, CalEvent* event);
|
||||
~CutHandler();
|
||||
|
||||
void InitCuts(const std::vector<ReconCut>& cuts);
|
||||
void InitEvent(CalEvent* event);
|
||||
inline const bool IsValid() const { return m_isValid; }
|
||||
|
||||
bool IsInside();
|
||||
|
||||
private:
|
||||
std::vector<ReconCut> m_cuts;
|
||||
CalEvent* m_eventPtr;
|
||||
bool m_isValid;
|
||||
|
||||
bool m_eventInit;
|
||||
bool m_cutInit;
|
||||
|
||||
std::unordered_map<std::string, double*> m_varMap;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
30
src/Detectors/FocalPlaneDetector.cpp
Normal file
30
src/Detectors/FocalPlaneDetector.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "FocalPlaneDetector.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
FocalPlaneDetector::FocalPlaneDetector() {}
|
||||
|
||||
FocalPlaneDetector::FocalPlaneDetector(const Parameters& params) :
|
||||
m_params(params)
|
||||
{
|
||||
}
|
||||
|
||||
FocalPlaneDetector::~FocalPlaneDetector() {}
|
||||
|
||||
double FocalPlaneDetector::GetRho(double xavg)
|
||||
{
|
||||
double rho = 0.0;
|
||||
for(size_t i=0; i< m_params.calParams.size(); i++)
|
||||
{
|
||||
rho += m_params.calParams[i]*std::pow(xavg, i);
|
||||
}
|
||||
return rho;
|
||||
}
|
||||
|
||||
double FocalPlaneDetector::GetP(double xavg, int Z)
|
||||
{
|
||||
double rho = GetRho(xavg);
|
||||
return Z*rho*m_params.B*s_qbrho2p;
|
||||
}
|
||||
}
|
38
src/Detectors/FocalPlaneDetector.h
Normal file
38
src/Detectors/FocalPlaneDetector.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#ifndef FOCAL_PLANE_DETECTOR_H
|
||||
#define FOCAL_PLANE_DETECTOR_H
|
||||
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
class FocalPlaneDetector
|
||||
{
|
||||
public:
|
||||
struct Parameters
|
||||
{
|
||||
double B;
|
||||
double angle;
|
||||
std::vector<double> calParams;
|
||||
};
|
||||
|
||||
FocalPlaneDetector();
|
||||
FocalPlaneDetector(const Parameters& params);
|
||||
~FocalPlaneDetector();
|
||||
|
||||
void Init(const Parameters& params) { m_params = params; }
|
||||
double GetRho(double xavg);
|
||||
double GetP(double xavg, int Z);
|
||||
inline double GetFPTheta() const { return m_params.angle*s_deg2rad; }
|
||||
|
||||
private:
|
||||
Parameters m_params;
|
||||
|
||||
//Constants
|
||||
static constexpr double s_lightspeed = 299792458.0; //1/s
|
||||
static constexpr double s_qbrho2p = 1.0e-9 * s_lightspeed; //MeV/(cm*kG)
|
||||
static constexpr double s_deg2rad = M_PI/180.0; //rad/deg
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
345
src/Detectors/SabreDetector.cpp
Normal file
345
src/Detectors/SabreDetector.cpp
Normal file
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
|
||||
Class which represents a single MMM detector in the SABRE array at FSU. Origial code by KGH, re-written by
|
||||
GWM.
|
||||
|
||||
Distances in meters, angles in radians.
|
||||
|
||||
The channel arrays have four points, one for each corner. The corners are
|
||||
as follows, as if looking BACK along beam (i.e. from the target's pov):
|
||||
|
||||
0---------------------1
|
||||
| |
|
||||
| | x
|
||||
| | <-----
|
||||
| | |
|
||||
| | |
|
||||
3---------------------2 y
|
||||
(z is hence positive along beam direction)
|
||||
|
||||
The channel numbers, also as looking back from target pov, are:
|
||||
|
||||
>> rings are 0 -- 15 from inner to outer:
|
||||
|
||||
15 -------------------
|
||||
14 -------------------
|
||||
13 -------------------
|
||||
.
|
||||
.
|
||||
.
|
||||
2 -------------------
|
||||
1 -------------------
|
||||
0 -------------------
|
||||
|
||||
>> wedges are 0 -- 7 moving counterclockwise:
|
||||
|
||||
7 6 ... 1 0
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
|
||||
|
||||
>> Note that the detector starts centered on the x-axis (central phi = 0) untilted, and then is rotated to wherever the frick
|
||||
it is supposed to go; phi = 90 is centered on y axis, pointing down towards the bottom of the scattering chamber
|
||||
|
||||
-- gwm, Dec 2020; based on the og code from kgh
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "SabreDetector.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
void PrintMatrix(TRotation& mat)
|
||||
{
|
||||
std::cout<<"XX: "<<mat.XX()<<" XY: "<<mat.XY()<<" XZ: "<<mat.XZ()<<std::endl;
|
||||
std::cout<<"YX: "<<mat.YX()<<" YY: "<<mat.YY()<<" YZ: "<<mat.YZ()<<std::endl;
|
||||
std::cout<<"ZX: "<<mat.ZX()<<" ZY: "<<mat.ZY()<<" ZZ: "<<mat.ZZ()<<std::endl;
|
||||
}
|
||||
|
||||
SabreDetector::SabreDetector() :
|
||||
m_phiCentral(0.0), m_tilt(0.0), m_translation(0.,0.,0.), m_norm_flat(0,0,1.0), m_drawingFlag(true), m_channelSmear(0.0, 1.0),
|
||||
m_detectorID(-1)
|
||||
{
|
||||
m_YRot.RotateY(-1.0*m_tilt);
|
||||
m_ZRot.RotateZ(m_phiCentral);
|
||||
|
||||
//Initialize the coordinate arrays
|
||||
m_ringCoords_flat.resize(s_nRings);
|
||||
m_ringCoords_tilt.resize(s_nRings);
|
||||
m_wedgeCoords_flat.resize(s_nWedges);
|
||||
m_wedgeCoords_tilt.resize(s_nWedges);
|
||||
for(int i=0; i<s_nRings; i++)
|
||||
{
|
||||
m_ringCoords_flat[i].resize(4);
|
||||
m_ringCoords_tilt[i].resize(4);
|
||||
}
|
||||
for(int i=0; i<s_nWedges; i++)
|
||||
{
|
||||
m_wedgeCoords_flat[i].resize(4);
|
||||
m_wedgeCoords_tilt[i].resize(4);
|
||||
}
|
||||
|
||||
m_deltaR_flat = s_Router - s_Rinner;
|
||||
m_deltaR_flat_ring = m_deltaR_flat/s_nRings;
|
||||
|
||||
CalculateCorners();
|
||||
}
|
||||
|
||||
SabreDetector::SabreDetector(const Parameters& params) :
|
||||
m_phiCentral(params.phiCenter), m_tilt(params.tilt), m_translation(0., 0., params.zOffset), m_norm_flat(0,0,1.0),
|
||||
m_drawingFlag(params.drawing), m_channelSmear(0.0, 1.0), m_detectorID(params.detID)
|
||||
{
|
||||
m_YRot.RotateY(-1.0*m_tilt); //clockwise rotation
|
||||
m_ZRot.RotateZ(m_phiCentral);
|
||||
|
||||
//Initialize coordinate arrays
|
||||
if(m_drawingFlag)
|
||||
{
|
||||
m_ringCoords_flat.resize(s_nRings);
|
||||
m_ringCoords_tilt.resize(s_nRings);
|
||||
m_wedgeCoords_flat.resize(s_nWedges);
|
||||
m_wedgeCoords_tilt.resize(s_nWedges);
|
||||
for(int i=0; i<s_nRings; i++)
|
||||
{
|
||||
m_ringCoords_flat[i].resize(4);
|
||||
m_ringCoords_tilt[i].resize(4);
|
||||
}
|
||||
for(int i=0; i<s_nWedges; i++)
|
||||
{
|
||||
m_wedgeCoords_flat[i].resize(4);
|
||||
m_wedgeCoords_tilt[i].resize(4);
|
||||
}
|
||||
|
||||
m_deltaR_flat = s_Router - s_Rinner;
|
||||
m_deltaR_flat_ring = m_deltaR_flat/s_nRings;
|
||||
m_deltaPhi_flat_wedge = s_deltaPhi_flat/s_nWedges;
|
||||
|
||||
CalculateCorners();
|
||||
}
|
||||
}
|
||||
|
||||
SabreDetector::~SabreDetector() {}
|
||||
|
||||
void SabreDetector::CalculateCorners() {
|
||||
|
||||
double x0, x1, x2, x3;
|
||||
double y0, y1, y2, y3;
|
||||
double z0, z1, z2, z3;
|
||||
|
||||
//Generate flat ring corner coordinates
|
||||
for(int i=0; i<s_nRings; i++)
|
||||
{
|
||||
x0 = (s_Rinner + m_deltaR_flat_ring*(i+1))*std::cos(-s_deltaPhi_flat/2.0);
|
||||
y0 = (s_Rinner + m_deltaR_flat_ring*(i+1))*std::sin(-s_deltaPhi_flat/2.0);
|
||||
z0 = 0.0;
|
||||
m_ringCoords_flat[i][0].SetXYZ(x0, y0, z0);
|
||||
|
||||
x1 = (s_Rinner + m_deltaR_flat_ring*(i))*std::cos(-s_deltaPhi_flat/2.0);
|
||||
y1 = (s_Rinner + m_deltaR_flat_ring*(i))*std::sin(-s_deltaPhi_flat/2.0);
|
||||
z1 = 0.0;
|
||||
m_ringCoords_flat[i][1].SetXYZ(x1, y1, z1);
|
||||
|
||||
x2 = (s_Rinner + m_deltaR_flat_ring*(i))*std::cos(s_deltaPhi_flat/2.0);
|
||||
y2 = (s_Rinner + m_deltaR_flat_ring*(i))*std::sin(s_deltaPhi_flat/2.0);
|
||||
z2 = 0.0;
|
||||
m_ringCoords_flat[i][2].SetXYZ(x2, y2, z2);
|
||||
|
||||
x3 = (s_Rinner + m_deltaR_flat_ring*(i+1))*std::cos(s_deltaPhi_flat/2.0);
|
||||
y3 = (s_Rinner + m_deltaR_flat_ring*(i+1))*std::sin(s_deltaPhi_flat/2.0);
|
||||
z3 = 0.0;
|
||||
m_ringCoords_flat[i][3].SetXYZ(x3, y3, z3);
|
||||
}
|
||||
|
||||
//Generate flat wedge corner coordinates
|
||||
for(int i=0; i<s_nWedges; i++)
|
||||
{
|
||||
x0 = s_Router * std::cos(-s_deltaPhi_flat/2.0 + i*m_deltaPhi_flat_wedge);
|
||||
y0 = s_Router * std::sin(-s_deltaPhi_flat/2.0 + i*m_deltaPhi_flat_wedge);
|
||||
z0 = 0.0;
|
||||
m_wedgeCoords_flat[i][0].SetXYZ(x0, y0, z0);
|
||||
|
||||
x1 = s_Rinner * std::cos(-s_deltaPhi_flat/2.0 + i*m_deltaPhi_flat_wedge);
|
||||
y1 = s_Rinner * std::sin(-s_deltaPhi_flat/2.0 + i*m_deltaPhi_flat_wedge);
|
||||
z1 = 0.0;
|
||||
m_wedgeCoords_flat[i][1].SetXYZ(x1, y1, z1);
|
||||
|
||||
x2 = s_Rinner * std::cos(-s_deltaPhi_flat/2.0 + (i+1)*m_deltaPhi_flat_wedge);
|
||||
y2 = s_Rinner * std::sin(-s_deltaPhi_flat/2.0 + (i+1)*m_deltaPhi_flat_wedge);
|
||||
z2 = 0.0;
|
||||
m_wedgeCoords_flat[i][2].SetXYZ(x2, y2, z2);
|
||||
|
||||
x3 = s_Router * std::cos(-s_deltaPhi_flat/2.0 + (i+1)*m_deltaPhi_flat_wedge);
|
||||
y3 = s_Router * std::sin(-s_deltaPhi_flat/2.0 + (i+1)*m_deltaPhi_flat_wedge);
|
||||
z3 = 0.0;
|
||||
m_wedgeCoords_flat[i][3].SetXYZ(x3, y3, z3);
|
||||
}
|
||||
|
||||
//Generate tilted rings
|
||||
for(int i=0; i<s_nRings; i++)
|
||||
{
|
||||
for(int j=0; j<4; j++)
|
||||
m_ringCoords_tilt[i][j] = TransformToTiltedFrame(m_ringCoords_flat[i][j]);
|
||||
}
|
||||
|
||||
//Generate tilted wedges
|
||||
for(int i=0; i<s_nWedges; i++)
|
||||
{
|
||||
for(int j=0; j<4; j++)
|
||||
m_wedgeCoords_tilt[i][j] = TransformToTiltedFrame(m_wedgeCoords_flat[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Given a unit vector (R=1, theta, phi) which corresponds to some particle's trajectory,
|
||||
determine whether that particle will intersect with this SABRE detector. If it does calculate
|
||||
the coordinates of the hit. The equation is as follows:
|
||||
|
||||
Rz(eta)*Ry(psi)*Flat_vector(R', theta'=PI/2, phi') + translation = Tilted_vector(R, theta, phi)
|
||||
|
||||
Where Rz is the ZRotation, Ry is the YRotation, F_vector is the vector of the coordinates in the flat detector frame,
|
||||
and Tilted_vector is the vector of the hit coordinates in the tilted frame. The theta and phi of the the Tilted_vector correspond
|
||||
to the input arguments of the function.
|
||||
|
||||
It checks to deterime whether or not the particle hits within the borders (read: edges) of the SABRE detector, and does not account for
|
||||
the spacing between rings and wedges.
|
||||
|
||||
!NOTE: This currently only applies to a configuration where there is no translation in x & y. The math becomes significantly messier in these cases.
|
||||
Also, don't use tan(). It's behavior near PI/2 makes it basically useless for these.
|
||||
*/
|
||||
TVector3 SabreDetector::GetTrajectoryCoordinates(double theta, double phi)
|
||||
{
|
||||
if(m_translation.X() != 0.0 || m_translation.Y() != 0.0)
|
||||
return TVector3();
|
||||
|
||||
//Calculate the *potential* phi in the flat detector
|
||||
double phi_numerator = std::cos(m_tilt)*(std::sin(phi)*std::cos(m_phiCentral) - std::sin(m_phiCentral)*std::cos(phi));
|
||||
double phi_denominator = std::cos(m_phiCentral)*std::cos(phi) + std::sin(m_phiCentral)*std::sin(phi);
|
||||
double phi_flat = std::atan2(phi_numerator, phi_denominator);
|
||||
if(phi_flat < 0) phi_flat += M_PI*2.0;
|
||||
|
||||
//Calculate the *potential* R in the flat detector
|
||||
double r_numerator = m_translation.Z()*std::cos(phi)*std::sin(theta);
|
||||
double r_denominator = std::cos(phi_flat)*std::cos(m_phiCentral)*std::cos(m_tilt)*std::cos(theta) - std::sin(phi_flat)*std::sin(m_phiCentral)*std::cos(theta) - std::cos(phi_flat)*std::sin(m_tilt)*std::cos(phi)*std::sin(theta);
|
||||
double r_flat = r_numerator/r_denominator;
|
||||
|
||||
//Calculate the distance from the origin to the hit on the detector
|
||||
double R_to_detector = (r_flat*std::cos(phi_flat)*std::sin(m_tilt) + m_translation.Z())/std::cos(theta);
|
||||
double xhit = R_to_detector*std::sin(theta)*std::cos(phi);
|
||||
double yhit = R_to_detector*std::sin(theta)*std::sin(phi);
|
||||
double zhit = R_to_detector*std::cos(theta);
|
||||
|
||||
|
||||
//Check to see if our flat coords fall inside the flat detector
|
||||
if(IsInside(r_flat, phi_flat))
|
||||
return TVector3(xhit, yhit, zhit);
|
||||
else
|
||||
return TVector3();
|
||||
}
|
||||
|
||||
/*
|
||||
Given a unit vector (R=1, theta, phi) which corresponds to some particle's trajectory,
|
||||
determine whether that particle will intersect with this SABRE detector. If it does determine
|
||||
which ring and wedge the hit occurs in. The equation is as follows:
|
||||
|
||||
Rz(eta)*Ry(psi)*Flat_vector(R', theta'=PI/2, phi') + translation = Tilted_vector(R, theta, phi)
|
||||
|
||||
Where Rz is the ZRotation, Ry is the YRotation, F_vector is the vector of the coordinates in the flat detector frame,
|
||||
and Tilted_vector is the vector of the hit coordinates in the tilted frame. The theta and phi of the the Tilted_vector correspond
|
||||
to the input arguments of the function.
|
||||
|
||||
Then using the flat coordinate R' and phi' determine which ring/wedge channels are hit. For precision purposes, the channel is not calculated, but
|
||||
rather found using comparisions. This method accounts for the spacing between rings and wedges.
|
||||
|
||||
!NOTE: This currently only applies to a configuration where there is no translation in x & y. The math becomes significantly messier in these cases.
|
||||
Also, don't use tan(). It's behavior near PI/2 makes it basically useless for these.
|
||||
*/
|
||||
std::pair<int, int> SabreDetector::GetTrajectoryRingWedge(double theta, double phi)
|
||||
{
|
||||
phi = phi < 0 ? 2.0*M_PI + phi : phi;
|
||||
if(m_translation.X() != 0.0 || m_translation.Y() != 0.0)
|
||||
return std::make_pair(-1, -1);
|
||||
|
||||
//Calculate the *potential* phi in the flat detector
|
||||
double phi_numerator = std::cos(m_tilt)*(std::sin(phi)*std::cos(m_phiCentral) - std::sin(m_phiCentral)*std::cos(phi));
|
||||
double phi_denominator = std::cos(m_phiCentral)*std::cos(phi) + std::sin(m_phiCentral)*std::sin(phi);
|
||||
double phi_flat = std::atan2(phi_numerator, phi_denominator);
|
||||
if(phi_flat < 0) phi_flat += M_PI*2.0;
|
||||
|
||||
//Calculate the *potential* R in the flat detector
|
||||
double r_numerator = m_translation.Z()*std::cos(phi)*std::sin(theta);
|
||||
double r_denominator = std::cos(phi_flat)*std::cos(m_phiCentral)*std::cos(m_tilt)*std::cos(theta) - std::sin(phi_flat)*std::sin(m_phiCentral)*std::cos(theta) - std::cos(phi_flat)*std::sin(m_tilt)*std::cos(phi)*std::sin(theta);
|
||||
double r_flat = r_numerator/r_denominator;
|
||||
|
||||
//Calculate the distance from the origin to the hit on the detector
|
||||
//double R_to_detector = (r_flat*std::cos(phi_flat)*std::sin(m_tilt) + m_translation.GetZ())/std::cos(theta);
|
||||
|
||||
//Check to see if our flat coords fall inside the flat detector
|
||||
if(IsInside(r_flat, phi_flat))
|
||||
{
|
||||
int ringch, wedgech;
|
||||
if(phi_flat > M_PI) phi_flat -= 2.0*M_PI; //Need phi in terms of [-deltaPhi_flat/2, deltaPhi_flat/2]
|
||||
for(int i=0; i<s_nRings; i++) {
|
||||
if(IsRingTopEdge(r_flat, i) || IsRingBottomEdge(r_flat, i))
|
||||
{ //If it falls in the interstrip spacing, kill it
|
||||
ringch = -1;
|
||||
break;
|
||||
}
|
||||
else if(IsRing(r_flat, i))
|
||||
{
|
||||
ringch = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(int i=0; i<s_nWedges; i++)
|
||||
{
|
||||
if(IsWedgeTopEdge(phi_flat, i) || IsWedgeBottomEdge(phi_flat, i))
|
||||
{ //If it falls in the interstrip spacing, kill it
|
||||
wedgech = -1;
|
||||
break;
|
||||
}
|
||||
else if(IsWedge(phi_flat, i))
|
||||
{
|
||||
wedgech = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return std::make_pair(ringch, wedgech);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_pair(-1,-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Given a ring/wedge of this SABRE detector, calculate the coordinates of a hit.
|
||||
Currently gives a point in the *center* of the pixel. Better method would be to
|
||||
randomly wiggle the point within the pixel. Method intended for use with data, or
|
||||
to smear out simulated data to mimic real data.
|
||||
*/
|
||||
TVector3 SabreDetector::GetHitCoordinates(int ringch, int wedgech)
|
||||
{
|
||||
if(!CheckRingChannel(ringch) || !CheckWedgeChannel(wedgech))
|
||||
return TVector3();
|
||||
|
||||
RandomGenerator& gen = RandomGenerator::GetInstance();
|
||||
double ringSmear = m_channelSmear(gen.GetGenerator());
|
||||
double wedgeSmear = m_channelSmear(gen.GetGenerator());
|
||||
double r_center = s_Rinner + (ringch + ringSmear)*m_deltaR_flat_ring;
|
||||
double phi_center = -s_deltaPhi_flat/2.0 + (wedgech + wedgeSmear)*m_deltaPhi_flat_wedge;
|
||||
double x = r_center*std::cos(phi_center);
|
||||
double y = r_center*std::sin(phi_center);
|
||||
double z = 0;
|
||||
|
||||
TVector3 hit(x, y, z);
|
||||
|
||||
return TransformToTiltedFrame(hit);
|
||||
}
|
||||
|
||||
}
|
203
src/Detectors/SabreDetector.h
Normal file
203
src/Detectors/SabreDetector.h
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
|
||||
Class which represents a single MMM detector in the SABRE array at FSU. Origial code by KGH, re-written by
|
||||
GWM.
|
||||
|
||||
Distances in meters, angles in radians.
|
||||
|
||||
The channel arrays have four points, one for each corner. The corners are
|
||||
as follows, as if looking BACK along beam (i.e. from the target's pov):
|
||||
|
||||
0---------------------1
|
||||
| |
|
||||
| | x
|
||||
| | <-----
|
||||
| | |
|
||||
| | |
|
||||
3---------------------2 y
|
||||
(z is hence positive along beam direction)
|
||||
|
||||
The channel numbers, also as looking back from target pov, are:
|
||||
|
||||
>> rings are 0 -- 15 from inner to outer:
|
||||
|
||||
15 -------------------
|
||||
14 -------------------
|
||||
13 -------------------
|
||||
.
|
||||
.
|
||||
.
|
||||
2 -------------------
|
||||
1 -------------------
|
||||
0 -------------------
|
||||
|
||||
>> wedges are 0 -- 7 moving counterclockwise:
|
||||
|
||||
7 6 ... 1 0
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
|
||||
|
||||
>> Note that the detector starts centered on the x-axis (central phi = 0) untilted, and then is rotated to wherever the frick
|
||||
it is supposed to go; phi = 90 is centered on y axis, pointing down towards the bottom of the scattering chamber
|
||||
|
||||
-- GWM, Dec 2020; based on the og code from kgh
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SABREDETECTOR_H
|
||||
#define SABREDETECTOR_H
|
||||
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
#include "TVector3.h"
|
||||
#include "TRotation.h"
|
||||
|
||||
#include "RandomGenerator.h"
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
class SabreDetector
|
||||
{
|
||||
public:
|
||||
struct Parameters
|
||||
{
|
||||
Parameters(double phi, double tilt, double z, bool draw, int id) :
|
||||
phiCenter(phi*M_PI/180.0), tilt(tilt*M_PI/180.0), zOffset(z), drawing(draw), detID(id)
|
||||
{
|
||||
}
|
||||
double phiCenter=0.0;
|
||||
double tilt=0.0;
|
||||
double zOffset=0.0;
|
||||
bool drawing=false;
|
||||
int detID=-1;
|
||||
};
|
||||
|
||||
SabreDetector();
|
||||
SabreDetector(const Parameters& params);
|
||||
~SabreDetector();
|
||||
|
||||
/*Return coordinates of the corners of each ring/wedge in SABRE*/
|
||||
inline TVector3 GetRingFlatCoords(int ch, int corner) { return m_drawingFlag && CheckRingLocation(ch, corner) ? m_ringCoords_flat[ch][corner] : TVector3(); }
|
||||
inline TVector3 GetWedgeFlatCoords(int ch, int corner) { return m_drawingFlag && CheckWedgeLocation(ch, corner) ? m_wedgeCoords_flat[ch][corner] : TVector3(); }
|
||||
inline TVector3 GetRingTiltCoords(int ch, int corner) { return m_drawingFlag && CheckRingLocation(ch, corner) ? m_ringCoords_tilt[ch][corner] : TVector3(); }
|
||||
inline TVector3 GetWedgeTiltCoords(int ch, int corner) { return m_drawingFlag && CheckWedgeLocation(ch, corner) ? m_wedgeCoords_tilt[ch][corner] : TVector3(); }
|
||||
|
||||
TVector3 GetTrajectoryCoordinates(double theta, double phi);
|
||||
std::pair<int, int> GetTrajectoryRingWedge(double theta, double phi);
|
||||
TVector3 GetHitCoordinates(int ringch, int wedgech);
|
||||
|
||||
inline const int GetDetectorID() const { return m_detectorID; }
|
||||
|
||||
/*Basic getters*/
|
||||
inline TVector3 GetNormTilted() { return TransformToTiltedFrame(m_norm_flat); }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/*Class constants*/
|
||||
static constexpr int s_nRings = 16;
|
||||
static constexpr int s_nWedges = 8;
|
||||
static constexpr double s_deg2rad = M_PI/180.0;
|
||||
static constexpr double s_Rinner = 0.0326;
|
||||
static constexpr double s_Router = 0.1351;
|
||||
static constexpr double s_deltaPhi_flat = 54.4 * M_PI/180.0;
|
||||
/*These are implicitly the width of the spacing between detector active strips*/
|
||||
static constexpr double position_tol = 0.0001; //0.1 mm position tolerance
|
||||
static constexpr double angular_tol = 0.1*M_PI/180.0; // 0.1 degree angular tolerance
|
||||
|
||||
void CalculateCorners();
|
||||
|
||||
/*Performs the transformation to the tilted,rotated,translated frame of the SABRE detector*/
|
||||
inline TVector3 TransformToTiltedFrame(TVector3& vector) { return (vector.Transform(m_YRot)).Transform(m_ZRot) + m_translation; }
|
||||
|
||||
/*Determine if a given channel/corner combo is valid*/
|
||||
inline bool CheckRingChannel(int ch) { return (ch<s_nRings && ch>=0) ? true : false; }
|
||||
inline bool CheckWedgeChannel(int ch) { return (ch<s_nWedges && ch >=0) ? true : false; }
|
||||
inline bool CheckCorner(int corner) { return (corner < 4 && corner >=0) ? true : false; }
|
||||
inline bool CheckRingLocation(int ch, int corner) { return CheckRingChannel(ch) && CheckCorner(corner); }
|
||||
inline bool CheckWedgeLocation(int ch, int corner) { return CheckWedgeChannel(ch) && CheckCorner(corner); }
|
||||
|
||||
/*
|
||||
For all of the calculations, need a limit precision to determine if values are actually equal or not
|
||||
Here the approx. size of the strip spacing is used as the precision.
|
||||
*/
|
||||
inline bool CheckPositionEqual(double val1,double val2) { return fabs(val1-val2) > position_tol ? false : true; }
|
||||
inline bool CheckAngleEqual(double val1,double val2) { return fabs(val1-val2) > angular_tol ? false : true; }
|
||||
|
||||
/*Determine if a hit is within the bulk detector*/
|
||||
inline bool IsInside(double r, double phi)
|
||||
{
|
||||
double phi_1 = s_deltaPhi_flat/2.0;
|
||||
double phi_2 = M_PI*2.0 - s_deltaPhi_flat/2.0;
|
||||
return (((r > s_Rinner && r < s_Router) || CheckPositionEqual(r, s_Rinner) || CheckPositionEqual(r, s_Router))
|
||||
&& (phi > phi_2 || phi < phi_1 || CheckAngleEqual(phi, phi_1) || CheckAngleEqual(phi, phi_2)));
|
||||
}
|
||||
|
||||
/*
|
||||
For a given radius/phi are you inside of a given ring/wedge channel,
|
||||
or are you on the spacing between these channels
|
||||
*/
|
||||
inline bool IsRing(double r, int ringch)
|
||||
{
|
||||
double ringtop = s_Rinner + m_deltaR_flat_ring*(ringch + 1);
|
||||
double ringbottom = s_Rinner + m_deltaR_flat_ring*(ringch);
|
||||
return (r>ringbottom && r<ringtop);
|
||||
}
|
||||
|
||||
inline bool IsRingTopEdge(double r, int ringch)
|
||||
{
|
||||
double ringtop = s_Rinner + m_deltaR_flat_ring*(ringch + 1);
|
||||
return CheckPositionEqual(r, ringtop);
|
||||
}
|
||||
|
||||
inline bool IsRingBottomEdge(double r, int ringch)
|
||||
{
|
||||
double ringbottom = s_Rinner + m_deltaR_flat_ring*(ringch);
|
||||
return CheckPositionEqual(r, ringbottom);
|
||||
}
|
||||
|
||||
inline bool IsWedge(double phi, int wedgech)
|
||||
{
|
||||
double wedgetop = -s_deltaPhi_flat/2.0 + m_deltaPhi_flat_wedge*(wedgech+1);
|
||||
double wedgebottom = -s_deltaPhi_flat/2.0 + m_deltaPhi_flat_wedge*(wedgech);
|
||||
return ((phi>wedgebottom && phi<wedgetop));
|
||||
}
|
||||
|
||||
inline bool IsWedgeTopEdge(double phi, int wedgech)
|
||||
{
|
||||
double wedgetop = -s_deltaPhi_flat/2.0 + m_deltaPhi_flat_wedge*(wedgech+1);
|
||||
return CheckAngleEqual(phi, wedgetop);
|
||||
}
|
||||
|
||||
inline bool IsWedgeBottomEdge(double phi, int wedgech)
|
||||
{
|
||||
double wedgebottom = -s_deltaPhi_flat/2.0 + m_deltaPhi_flat_wedge*(wedgech);
|
||||
return CheckAngleEqual(phi, wedgebottom);
|
||||
}
|
||||
|
||||
|
||||
/*Class data*/
|
||||
double m_phiCentral, m_tilt;
|
||||
TVector3 m_translation;
|
||||
TRotation m_YRot;
|
||||
TRotation m_ZRot;
|
||||
double m_deltaR_flat, m_deltaR_flat_ring, m_deltaPhi_flat_wedge;
|
||||
TVector3 m_norm_flat;
|
||||
bool m_drawingFlag;
|
||||
int m_detectorID;
|
||||
|
||||
std::uniform_real_distribution<double> m_channelSmear;
|
||||
|
||||
std::vector<std::vector<TVector3>> m_ringCoords_flat, m_wedgeCoords_flat;
|
||||
std::vector<std::vector<TVector3>> m_ringCoords_tilt, m_wedgeCoords_tilt;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
222
src/EnergyLoss/EnergyLoss.cpp
Normal file
222
src/EnergyLoss/EnergyLoss.cpp
Normal file
|
@ -0,0 +1,222 @@
|
|||
#include "EnergyLoss.h"
|
||||
#include "EnergyLossConstants.h"
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
namespace EnergyLoss {
|
||||
|
||||
double GetEnergyLoss(const Parameters& params)
|
||||
{
|
||||
|
||||
if(params.thickness == 0.0 || params.energy == 0.0 || params.ZP == 0)
|
||||
return 0.0;
|
||||
|
||||
|
||||
double energyFinal = params.energy;
|
||||
double xTraversed = 0;
|
||||
double xStep = 0.25*params.thickness; //initial step in x
|
||||
double energyStep = GetTotalStoppingPower(params, energyFinal)*xStep/1000.0; //initial step in e
|
||||
double energyThreshold = 0.05*params.energy;
|
||||
|
||||
int depth=0;
|
||||
|
||||
while(true)
|
||||
{
|
||||
//If intial guess of step size is too large, shrink until in range
|
||||
if(energyStep/energyFinal > maxFracStep && depth < maxDepth)
|
||||
{
|
||||
depth++;
|
||||
xStep *= 0.5;
|
||||
energyStep = GetTotalStoppingPower(params, energyFinal)*xStep/1000.0;
|
||||
}
|
||||
else if((xStep + xTraversed) >= params.thickness)
|
||||
{ //last chunk
|
||||
xStep = params.thickness - xTraversed; //get valid portion of last chunk
|
||||
energyFinal -= GetTotalStoppingPower(params, energyFinal)*xStep/1000.0;
|
||||
if(energyFinal <= energyThreshold)
|
||||
return params.energy;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if(depth == maxDepth)
|
||||
{
|
||||
return params.energy;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTraversed += xStep;
|
||||
energyStep = GetTotalStoppingPower(params, energyFinal)*xStep/1000.0;
|
||||
energyFinal -= energyStep;
|
||||
if(energyFinal <= energyThreshold)
|
||||
return params.energy;
|
||||
}
|
||||
}
|
||||
return params.energy - energyFinal;
|
||||
}
|
||||
|
||||
double GetReverseEnergyLoss(const Parameters& params)
|
||||
{
|
||||
double energyInitial = params.energy;
|
||||
double xTraversed = 0.0;
|
||||
double xStep = 0.25*params.thickness; //initial step in x
|
||||
double energyStep = GetTotalStoppingPower(params, energyInitial)*xStep/1000.0; //initial step in E
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(energyStep/energyInitial > maxFracStep)
|
||||
{
|
||||
xStep *= 0.5;
|
||||
energyStep = GetTotalStoppingPower(params, energyInitial)*xStep/1000.0;
|
||||
}
|
||||
else if (xTraversed+xStep > params.thickness)
|
||||
{
|
||||
xStep = params.thickness - xTraversed;
|
||||
energyInitial += GetTotalStoppingPower(params, energyInitial)*xStep/1000.0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTraversed += xStep;
|
||||
energyStep = GetTotalStoppingPower(params, energyInitial)*xStep/1000.0;
|
||||
energyInitial += energyStep;
|
||||
}
|
||||
}
|
||||
|
||||
return energyInitial-params.energy;
|
||||
}
|
||||
|
||||
/*Wrapper function for aquiring total stopping (elec + nuc)*/
|
||||
double GetTotalStoppingPower(const Parameters& params, double current_energy)
|
||||
{
|
||||
if(params.ZP == 0)
|
||||
return GetNuclearStoppingPower(params, current_energy);
|
||||
|
||||
return GetElectronicStoppingPower(params, current_energy)+GetNuclearStoppingPower(params, current_energy);
|
||||
}
|
||||
|
||||
/*Charge rel to H*/
|
||||
double GetElectronicStoppingPower(const Parameters& params, double current_energy)
|
||||
{
|
||||
//Wants in units of keV
|
||||
current_energy *= 1000.0;
|
||||
double ePerU = current_energy/params.massP;
|
||||
std::vector<double> values;
|
||||
if(ePerU > maxHEperU)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
else if (ePerU > 1000.0)
|
||||
{
|
||||
for(auto& z: params.ZT)
|
||||
values.push_back(Hydrogen_dEdx_High(ePerU, params.massP, current_energy, z));
|
||||
}
|
||||
else if (ePerU > 10.0)
|
||||
{
|
||||
for(auto& z: params.ZT)
|
||||
values.push_back(Hydrogen_dEdx_Med(ePerU, z));
|
||||
}
|
||||
else if (ePerU > 0.0)
|
||||
{
|
||||
for(auto& z: params.ZT)
|
||||
values.push_back(Hydrogen_dEdx_Low(ePerU, z));
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if(values.size() == 0)
|
||||
return 0.0; //bad
|
||||
|
||||
if(params.ZP > 1)
|
||||
{ //not hydrogen, need to account for effective charge
|
||||
for(unsigned int i=0; i<values.size(); i++)
|
||||
values[i] *= CalculateEffectiveChargeRatio(ePerU, params.ZP, params.ZT[i]);
|
||||
}
|
||||
|
||||
double stopping_total = 0;
|
||||
double conversion_factor = 0;
|
||||
for(size_t i=0; i< params.ZT.size(); i++)
|
||||
{
|
||||
conversion_factor += params.composition[i]*naturalMassList[params.ZT[i]];
|
||||
stopping_total += values[i]*params.composition[i];
|
||||
}
|
||||
stopping_total *= avogadro/conversion_factor;
|
||||
|
||||
return stopping_total;
|
||||
}
|
||||
|
||||
//Returns units of keV/(ug/cm^2)
|
||||
double GetNuclearStoppingPower(const Parameters& params, double energy)
|
||||
{
|
||||
energy *= 1000.0;
|
||||
double stopping_total = 0.0;
|
||||
double sn, x, epsilon, conversion_factor, massT;
|
||||
for(size_t i=0; i<params.ZT.size(); i++)
|
||||
{
|
||||
massT = naturalMassList[params.ZT[i]];
|
||||
x = (params.massP + massT) * std::sqrt(std::pow(params.ZP, 2.0/3.0) + std::pow(params.ZT[i], 2.0/3.0));
|
||||
epsilon = 32.53*massT*energy/(params.ZP*params.ZT[i]*x);
|
||||
sn = 8.462*(0.5*std::log(1.0+epsilon)/(epsilon+0.10718*std::pow(epsilon, 0.37544)))*params.ZP*params.ZT[i]*params.massP/x;
|
||||
conversion_factor = avogadro/massT;
|
||||
stopping_total += sn*conversion_factor*params.composition[i];
|
||||
}
|
||||
|
||||
return stopping_total;
|
||||
}
|
||||
|
||||
double Hydrogen_dEdx_Low(double ePerU, int z)
|
||||
{
|
||||
return std::sqrt(ePerU)*hydrogenCoefficients[z][0];
|
||||
}
|
||||
|
||||
double Hydrogen_dEdx_Med(double ePerU, int z)
|
||||
{
|
||||
double x = hydrogenCoefficients[z][1]*std::pow(ePerU, 0.45);
|
||||
double y = hydrogenCoefficients[z][2]/ePerU * std::log(1.0+hydrogenCoefficients[z][3]/ePerU+hydrogenCoefficients[z][4]*ePerU);
|
||||
return x*y/(x+y);
|
||||
}
|
||||
|
||||
double Hydrogen_dEdx_High(double ePerU, double massP, double energy, int z)
|
||||
{
|
||||
energy /= 1000.0; //back to MeV for ease of beta calc
|
||||
double beta_sq = energy * (energy+2.0*massP/mev2u)/std::pow(energy+massP/mev2u, 2.0);
|
||||
double alpha = hydrogenCoefficients[z][5]/beta_sq;
|
||||
double epsilon = hydrogenCoefficients[z][6]*beta_sq/(1.0-beta_sq) - beta_sq - hydrogenCoefficients[z][7];
|
||||
for(int i=1; i<5; i++)
|
||||
epsilon += hydrogenCoefficients[z][7+i]*std::pow(std::log(ePerU), i);
|
||||
|
||||
return alpha * std::log(epsilon);
|
||||
}
|
||||
|
||||
/*Charge rel to H*/
|
||||
double CalculateEffectiveChargeRatio(double ePerU, int zp, int z)
|
||||
{
|
||||
double z_ratio;
|
||||
if(zp == 2)
|
||||
{
|
||||
double ln_epu = std::log(ePerU);
|
||||
double gamma = 1.0+(0.007+0.00005*z)*std::exp(-std::pow(7.6-ln_epu,2.0));
|
||||
double alpha = 0.7446 + 0.1429*ln_epu + 0.01562*std::pow(ln_epu, 2.0) - 0.00267*std::pow(ln_epu,3.0)
|
||||
+ 1.338E-6*std::pow(ln_epu,8.0);
|
||||
z_ratio = gamma*(1.0-std::exp(-alpha))*2.0;
|
||||
}
|
||||
else if (zp == 3)
|
||||
{
|
||||
double ln_epu = std::log(ePerU);
|
||||
double gamma = 1.0+(0.007+0.00005*z)*std::exp(-std::pow(7.6-ln_epu,2.0));
|
||||
double alpha = 0.7138+0.002797*ePerU+1.348E-6*std::pow(ePerU, 2.0);
|
||||
z_ratio = gamma*(1-std::exp(-alpha))*3.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double B = 0.886*std::pow(ePerU/25.0, 0.5)/std::pow(zp, 2.0/3.0);
|
||||
double A = B + 0.0378*std::sin(M_PI/2.0*B);
|
||||
z_ratio = (1.0 - std::exp(-A)*(1.034-0.1777*std::exp(-0.08114*zp)))*zp;
|
||||
}
|
||||
return z_ratio*z_ratio; //for stopping power uses ratio sq.
|
||||
}
|
||||
}
|
||||
}
|
47
src/EnergyLoss/EnergyLoss.h
Normal file
47
src/EnergyLoss/EnergyLoss.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
|
||||
EnergyLoss.h
|
||||
Code for calculating the energy loss of a charged, massive particle through an arbitrary medium.
|
||||
Based on code written by D.W. Visser at Yale for the original SPANC. Uses energy loss calulations
|
||||
described by Ziegler in various SRIM textbooks.
|
||||
|
||||
Written by G.W. McCann Aug. 2020
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ENERGYLOSS_H
|
||||
#define ENERGYLOSS_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
namespace EnergyLoss {
|
||||
|
||||
struct Parameters
|
||||
{
|
||||
int ZP;
|
||||
double massP;
|
||||
std::vector<int> ZT;
|
||||
std::vector<double> composition; //percent composition
|
||||
double energy;
|
||||
double thickness;
|
||||
};
|
||||
|
||||
//Main integration functions
|
||||
double GetEnergyLoss(const Parameters& params);
|
||||
double GetReverseEnergyLoss(const Parameters& params);
|
||||
|
||||
//Helpers
|
||||
double GetTotalStoppingPower(const Parameters& params, double current_energy);
|
||||
double GetElectronicStoppingPower(const Parameters& params, double current_energy);
|
||||
double GetNuclearStoppingPower(const Parameters& params, double current_energy);
|
||||
double Hydrogen_dEdx_Low(double ePerU, int z);
|
||||
double Hydrogen_dEdx_Med(double ePerU, int z);
|
||||
double Hydrogen_dEdx_High(double ePerU, double massP, double energy, int z);
|
||||
double CalculateEffectiveChargeRatio(double ePerU, int zp, int z);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
147
src/EnergyLoss/EnergyLossConstants.h
Normal file
147
src/EnergyLoss/EnergyLossConstants.h
Normal file
|
@ -0,0 +1,147 @@
|
|||
#ifndef ELOSS_TABLES_H
|
||||
#define ELOSS_TABLES_H
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
namespace EnergyLoss {
|
||||
|
||||
static constexpr double maxFracStep = 0.001;
|
||||
static constexpr int maxDepth = 50;
|
||||
static constexpr double maxHEperU = 100000.0;
|
||||
static constexpr double avogadro = 0.60221367; //N_A times 10^(-24) for converting
|
||||
static constexpr double mev2u = 1.0/931.4940954;
|
||||
static constexpr double HMass = 938.27231; //MeV, for beta calc
|
||||
|
||||
#define MAX_Z 93 //Maximum number of elements for which we have hydrogen coefficients
|
||||
|
||||
/*Atomic Masses for elements H through U. Taken from ELAST data*/
|
||||
static constexpr double naturalMassList[MAX_Z] =
|
||||
{
|
||||
0,
|
||||
1.00797, 4.0026, 6.939, 9.0122, 10.818,
|
||||
12.01115, 14.0067, 15.9994, 18.99984, 20.183,
|
||||
22.9898, 24.312, 26.9815, 28.086, 30.9738,
|
||||
32.064, 35.453, 39.948, 39.102, 40.08,
|
||||
44.956, 47.90, 50.942, 51.996, 54.938,
|
||||
55.847, 58.933, 58.71, 63.54, 65.37,
|
||||
69.72, 72.59, 74.922, 78.96, 79.909,
|
||||
83.80, 85.47, 87.62, 88.909, 91.22,
|
||||
92.906, 95.94, 98., 101.07, 102.905,
|
||||
106.4, 107.87, 112.4, 114.82, 118.69,
|
||||
121.75, 127.60, 126.904, 131.3, 132.905,
|
||||
137.34, 138.91, 140.12, 140.907, 144.24,
|
||||
146., 150.35, 151.96, 157.25, 158.924,
|
||||
162.50, 164.93, 167.26, 168.934, 173.04,
|
||||
174.97, 178.49, 180.948, 183.85, 186.2,
|
||||
190.2, 192.2, 195.09, 196.967, 200.59,
|
||||
204.37, 207.19, 208.98, 209., 210.,
|
||||
222., 223., 226., 227., 232.038,
|
||||
231., 238.03
|
||||
};
|
||||
|
||||
/*Stopping power coefficients for hydrogen into Z
|
||||
*Taken from Ziegler, Hydrogen Stopping Powers and Ranges in All Elements, Volume 3 of
|
||||
*The Stopping and Ranges of Ions in Matter, 1977, Pergamon Press Inc.
|
||||
*Expanded table for method given in O.G. Spanc
|
||||
*Note: some elements represent extrapolations when there was no data to fit
|
||||
*/
|
||||
static constexpr double hydrogenCoefficients[MAX_Z][12] =
|
||||
{
|
||||
/*Blank*/{0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.},
|
||||
/*H*/{1.262,1.44,242.6,1.2E4,0.1159,0.0005099,5.436E4,-5.052,2.049,-0.3044,0.01966,-0.0004659},
|
||||
/*He*/{1.229,1.397,484.5,5873,0.05225,0.00102,2.451E4,-2.158,0.8278,-0.1172,0.007259,-0.000166},
|
||||
/*Li*/{1.411,1.6,725.6,3013,0.04578,0.00153,2.147E4,-0.5831,0.562,-0.1183,0.009298,-0.0002498},
|
||||
/*Be*/{2.248,2.59,966,153.8,0.03475,0.002039,1.63E4,0.2779,0.1745,-0.05684,0.005155,-0.0001488},
|
||||
/*B*/{2.474,2.815,1206,1060,0.02855,0.002549,1.345E4,-2.445,1.283,-0.2205,0.0156,-0.000393},
|
||||
/*C*/{2.631,2.989,1445,957.2,0.02819,0.003059,1.322E4,-4.38,2.044,-0.3283,0.02221,-0.0005417},
|
||||
/*N*/{2.954,3.35,1683,1900,0.02513,0.003569,1.179E4,-5.054,2.325,-0.3713,0.02506,-0.0006109},
|
||||
/*O*/{2.652,3,1920,2000,0.0223,0.004079,1.046E4,-6.734,3.019,-0.4748,0.03171,-0.0007669},
|
||||
/*F*/{2.085,2.352,2157,2634,0.01816,0.004589,8517,-5.571,2.449,-0.3781,0.02483,-0.0005919},
|
||||
/*Ne*/{1.951,2.199,2393,2699,0.01568,0.005099,7353,-4.408,1.879,-0.2814,0.01796,-0.0004168},
|
||||
/*Na*/{2.542,2.869,2628,1854,0.01472,0.005609,6905,-4.959,2.073,-0.3054,0.01921,-0.0004403},
|
||||
/*Mg*/{3.792,4.293,2862,1009,0.01397,0.006118,6551,-5.51,2.266,-0.3295,0.02047,-0.0004637},
|
||||
/*Al*/{4.154,4.739,2766,164.5,0.02023,0.006628,6309,-6.061,2.46,-0.3535,0.02173,-0.0004871},
|
||||
/*Si*/{4.15,4.7,3329,550,0.01321,0.007138,6194,-6.294,2.538,-0.3628,0.0222,-0.0004956},
|
||||
/*P*/{3.232,3.647,3561,1560,0.01267,0.007648,5942,-6.527,2.616,-0.3721,0.02267,-0.000504},
|
||||
/*S*/{3.447,3.891,3792,1219,0.01211,0.008158,5678,-6.761,2.694,-0.3814,0.02314,-0.0005125},
|
||||
/*Cl*/{5.047,5.714,4023,878.6,0.01178,0.008668,5524,-6.994,2.773,-0.3907,0.02361,-0.0005209},
|
||||
/*Ar*/{5.731,6.5,4253,530,0.01123,0.009178,5268,-7.227,2.851,-0.4,0.02407,-0.0005294},
|
||||
/*K*/{5.151,5.833,4482,545.7,0.01129,0.009687,5295,-7.44,2.923,-0.4094,0.02462,-0.0005411},
|
||||
/*Ca*/{5.521,6.252,4710,553.3,0.01112,0.0102,5214,-7.653,2.995,-0.4187,0.02516,-0.0005529},
|
||||
/*Sc*/{5.201,5.884,4938,560.9,0.009995,0.01071,4688,-8.012,3.123,-0.435,0.02605,-0.0005707},
|
||||
/*Ti*/{4.862,5.496,5165,568.5,0.009474,0.01122,4443,-8.371,3.251,-0.4513,0.02694,-0.0005886},
|
||||
/*V*/{4.48,5.055,5391,952.3,0.009117,0.01173,4276,-8.731,3.379,-0.4676,0.02783,-0.0006064},
|
||||
/*Cr*/{3.983,4.489,5616,1336,0.008413,0.01224,3946,-9.09,3.507,-0.4838,0.02872,-0.0006243},
|
||||
/*Mn*/{3.469,3.907,5725,1461,0.008829,0.01275,3785,-9.449,3.635,-0.5001,0.02961,-0.0006421},
|
||||
/*Fe*/{3.519,3.963,6065,1243,0.007782,0.01326,3650,-9.809,3.763,-0.5164,0.0305,-0.00066},
|
||||
/*Co*/{3.14,3.535,6288,1372,0.007361,0.01377,3453,-10.17,3.891,-0.5327,0.03139,-0.0006779},
|
||||
/*Ni*/{3.553,4.004,6205,555.1,0.008763,0.01428,3297,-10.53,4.019,-0.549,0.03229,-0.0006957},
|
||||
/*Cu*/{3.696,4.175,4673,387.8,0.02188,0.01479,3174,-11.18,4.252,-0.5791,0.03399,-0.0007314},
|
||||
/*Zn*/{4.21,4.75,6953,295.2,0.006809,0.0153,3194,-11.57,4.394,-0.598,0.03506,-0.0007537},
|
||||
/*Ga*/{5.041,5.697,7173,202.6,0.006725,0.01581,3154,-11.95,4.537,-0.6169,0.03613,-0.0007759},
|
||||
/*Ge*/{5.554,6.3,6496,110,0.009689,0.01632,3097,-12.34,4.68,-0.6358,0.03721,-0.0007981},
|
||||
/*As*/{5.323,6.012,7611,292.5,0.006447,0.01683,3024,-12.72,4.823,-0.6547,0.03828,-0.0008203},
|
||||
/*Se*/{5.874,6.656,7395,117.5,0.007684,0.01734,3006,-13.11,4.965,-0.6735,0.03935,-0.0008425},
|
||||
/*Br*/{5.611,6.335,8046,365.2,0.006244,0.01785,2928,-13.4,5.083,-0.6906,0.04042,-0.0008675},
|
||||
/*Kr*/{6.411,7.25,8262,220,0.006087,0.01836,2855,-13.69,5.2,-0.7076,0.0415,-0.0008925},
|
||||
/*Rb*/{5.694,6.429,8478,292.9,0.006087,0.01886,2855,-13.92,5.266,-0.714,0.04173,-0.0008943},
|
||||
/*Sr*/{6.339,7.159,8693,330.3,0.006003,0.01937,2815,-14.14,5.331,-0.7205,0.04196,-0.0008962},
|
||||
/*Y*/{6.407,7.234,8907,367.8,0.005889,0.01988,2762,-14.36,5.397,-0.7269,0.04219,-0.000898},
|
||||
/*Zr*/{6.734,7.603,9120,405.2,0.005765,0.02039,2704,-14.59,5.463,-0.7333,0.04242,-0.0008998},
|
||||
/*Nb*/{6.902,7.791,9333,442.7,0.005587,0.0209,2621,-16.22,6.094,-0.8225,0.04791,-0.001024},
|
||||
/*Mo*/{6.425,7.248,9545,480.2,0.005367,0.02141,2517,-17.85,6.725,-0.9116,0.05339,-0.001148},
|
||||
/*Tc*/{6.799,7.671,9756,517.6,0.005315,0.02192,2493,-17.96,6.752,-0.9135,0.05341,-0.001147},
|
||||
/*Ru*/{6.108,6.887,9966,555.1,0.005151,0.02243,2416,-18.07,6.779,-0.9154,0.05342,-0.001145},
|
||||
/*Rh*/{5.924,6.677,1.018E4,592.5,0.004919,0.02294,2307,-18.18,6.806,-0.9173,0.05343,-0.001143},
|
||||
/*Pd*/{5.238,5.9,1.038E4,630,0.004758,0.02345,2231,-18.28,6.833,-0.9192,0.05345,-0.001142},
|
||||
/*Ag*/{5.623,6.354,7160,337.6,0.01394,0.02396,2193,-18.39,6.86,-0.9211,0.05346,-0.00114},
|
||||
/*Cd*/{5.814,6.554,1.08E4,355.5,0.004626,0.02447,2170,-18.62,6.915,-0.9243,0.0534,-0.001134},
|
||||
/*In*/{6.23,7.024,1.101E4,370.9,0.00454,0.02498,2129,-18.85,6.969,-0.9275,0.05335,-0.001127},
|
||||
/*Sn*/{6.41,7.227,1.121E4,386.4,0.004474,0.02549,2099,-19.07,7.024,-0.9308,0.05329,-0.001121},
|
||||
/*Sb*/{7.5,8.48,8608,348,0.009074,0.026,2069,-19.57,7.225,-0.9603,0.05518,-0.001165},
|
||||
/*Te*/{6.979,7.871,1.162E4,392.4,0.004402,0.02651,2065,-20.07,7.426,-0.9899,0.05707,-0.001209},
|
||||
/*I*/{7.725,8.716,1.183E4,394.8,0.004376,0.02702,2052,-20.56,7.627,-1.019,0.05896,-0.001254},
|
||||
/*Xe*/{8.231,9.289,1.203E4,397.3,0.004384,0.02753,2056,-21.06,7.828,-1.049,0.06085,-0.001298},
|
||||
/*Cs*/{7.287,8.218,1.223E4,399.7,0.004447,0.02804,2086,-20.4,7.54,-1.004,0.05782,-0.001224},
|
||||
/*Ba*/{7.899,8.911,1.243E4,402.1,0.004511,0.02855,2116,-19.74,7.252,-0.9588,0.05479,-0.001151},
|
||||
/*La*/{8.041,9.071,1.263E4,404.5,0.00454,0.02906,2129,-19.08,6.964,-0.9136,0.05176,-0.001077},
|
||||
/*Ce*/{7.489,8.444,1.283E4,406.9,0.00442,0.02957,2073,-18.43,6.677,-0.8684,0.04872,-0.001003},
|
||||
/*Pr*/{7.291,8.219,1.303E4,409.3,0.004298,0.03008,2016,-17.77,6.389,-0.8233,0.04569,-0.0009292},
|
||||
/*Nd*/{7.098,8,1.323E4,411.8,0.004182,0.03059,1962,-17.11,6.101,-0.7781,0.04266,-0.0008553},
|
||||
/*Pm*/{6.91,7.786,1.343E4,414.2,0.00405,0.0311,1903,-16.45,5.813,-0.733,0.03963,-0.0007815},
|
||||
/*Sm*/{6.728,7.58,1.362E4,416.6,0.003976,0.03161,1865,-15.79,5.526,-0.6878,0.0366,-0.0007077},
|
||||
/*Eu*/{6.551,7.38,1.382E4,419,0.003877,0.03212,1819,-15.13,5.238,-0.6426,0.03357,-0.0006339},
|
||||
/*Gd*/{6.739,7.592,1.402E4,421.4,0.003863,0.03263,1812,-14.47,4.95,-0.5975,0.03053,-0.0005601},
|
||||
/*Tb*/{6.212,6.996,1.421E4,423.9,0.003725,0.03314,1747,-14.56,4.984,-0.6022,0.03082,-0.0005668},
|
||||
/*Dy*/{5.517,6.21,1.44E4,426.3,0.003632,0.03365,1703,-14.65,5.018,-0.6069,0.03111,-0.0005734},
|
||||
/*Ho*/{5.219,5.874,1.46E4,428.7,0.003498,0.03416,1640,-14.74,5.051,-0.6117,0.03141,-0.0005801},
|
||||
/*Er*/{5.071,5.706,1.479E4,433,0.003405,0.03467,1597,-14.83,5.085,-0.6164,0.0317,-0.0005867},
|
||||
/*Tm*/{4.926,5.542,1.498E4,433.5,0.003342,0.03518,1567,-14.91,5.119,-0.6211,0.03199,-0.0005933},
|
||||
/*Yb*/{4.787, 5.386,1.517E4,435.9,0.003292,0.03569,1544,-15,5.153,-0.6258,0.03228,-0.0006},
|
||||
/*Lu*/{4.893, 5.505,1.536E4,438.4,0.003243,0.0362,1521,-15.09,5.186,-0.6305,0.03257,-0.0006066},
|
||||
/*Hf*/{5.028, 5.657,1.555E4,440.8,0.003195,0.03671,1499,-15.18,5.22,-0.6353,0.03286,-0.0006133},
|
||||
/*Ta*/{4.738, 5.329,1.574E4,443.2,0.003186,0.03722,1494,-15.27,5.254,-0.64,0.03315,-0.0006199},
|
||||
/*W*/{4.574, 5.144,1.593E4,442.4,0.003144,0.03773,1475,-15.67,5.392,-0.6577,0.03418,-0.0006426},
|
||||
/*Re*/{5.2, 5.851,1.612E4,441.6,0.003122,0.03824,1464,-16.07,5.529,-0.6755,0.03521,-0.0006654},
|
||||
/*Os*/{5.07, 5.704,1.63E4,440.9,0.003082,0.03875,1446,-16.47,5.667,-0.6932,0.03624,-0.0006881},
|
||||
/*Ir*/{4.945, 5.563,1.649E4,440.1,0.002965,0.03926,1390,-16.88,5.804,-0.711,0.03727,-0.0007109},
|
||||
/*Pt*/{4.476, 5.034,1.667E4,439.3,0.002871,0.03977,1347,-17.28,5.942,-0.7287,0.0383,-0.0007336},
|
||||
/*Au*/{4.856, 5.46,1.832E4,438.5,0.002542,0.04028,1354,-17.02,5.846,-0.7149,0.0374,-0.0007114},
|
||||
/*Hg*/{4.308, 4.843,1.704E4,487.8,0.002882,0.04079,1352,-17.84,6.183,-0.7659,0.04076,-0.0007925},
|
||||
/*Tl*/{4.723, 5.311,1.722E4,537,0.002913,0.0413,1366,-18.66,6.52,-0.8169,0.04411,-0.0008737},
|
||||
/*Pb*/{5.319, 5.982,1.74E4,586.3,0.002871,0.04181,1347,-19.48,6.857,-0.8678,0.04747,-0.0009548},
|
||||
/*Bi*/{5.956, 6.7,1.78E4,677,0.00266,0.04232,1336,-19.55,6.871,-0.8686,0.04748,-0.0009544},
|
||||
/*Po*/{6.158, 6.928,1.777E4,586.3,0.002812,0.04283,1319,-19.62,6.884,-0.8694,0.04748,-0.000954},
|
||||
/*At*/{6.204, 6.979,1.795E4,586.3,0.002776,0.04334,1302,-19.69,6.898,-0.8702,0.04749,-0.0009536},
|
||||
/*Rn*/{6.181, 6.954,1.812E4,586.3,0.002748,0.04385,1289,-19.76,6.912,-0.871,0.04749,-0.0009532},
|
||||
/*Fr*/{6.949, 7.82,1.83E4,586.3,0.002737,0.04436,1284,-19.83,6.926,-0.8718,0.0475,-0.0009528},
|
||||
/*Ra*/{7.506, 8.448,1.848E4,586.3,0.002727,0.04487,1279,-19.9,6.94,-0.8726,0.04751,-0.0009524},
|
||||
/*Ac*/{7.649, 8.609,1.866E4,586.3,0.002697,0.04538,1265,-19.97,6.953,-0.8733,0.04751,-0.000952},
|
||||
/*Th*/{7.71, 8.679,1.883E4,586.3,0.002641,0.04589,1239,-20.04,6.967,-0.8741,0.04752,-0.0009516},
|
||||
/*Pa*/{7.407, 8.336,1.901E4,586.3,0.002603,0.0464,1221,-20.11,6.981,-0.8749,0.04752,-0.0009512},
|
||||
/*U*/{7.29, 8.204,1.918E4,586.3,0.002573,0.04691,1207,-20.18,6.995,-0.8757,0.04753,-0.0009508}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
117
src/EnergyLoss/Target.cpp
Normal file
117
src/EnergyLoss/Target.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
|
||||
Target.cpp
|
||||
A basic target unit for use in the SPANCRedux environment. A target
|
||||
is defined as a single compound with elements Z,A of a given stoichiometry
|
||||
Holds an energy loss class
|
||||
|
||||
Based on code by D.W. Visser written at Yale for the original SPANC
|
||||
|
||||
Written by G.W. McCann Aug. 2020
|
||||
|
||||
*/
|
||||
#include "Target.h"
|
||||
#include "EnergyLossConstants.h"
|
||||
#include "MassLookup.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
Target::Target() :
|
||||
m_totalThickness(0.0), m_isValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*Targets must be of known thickness*/
|
||||
Target::Target(const std::vector<int>& z, const std::vector<int>& stoich, double thick) :
|
||||
m_isValid(false)
|
||||
{
|
||||
SetParameters(z, stoich, thick);
|
||||
}
|
||||
|
||||
Target::~Target()
|
||||
{
|
||||
}
|
||||
|
||||
/*Set target elements of given Z, A, S*/
|
||||
void Target::SetParameters(const std::vector<int>& z, const std::vector<int>& stoich, double thick)
|
||||
{
|
||||
m_params.ZT = z;
|
||||
double denom = 0;
|
||||
for(auto& s : stoich)
|
||||
denom += s;
|
||||
for(auto& s : stoich)
|
||||
m_params.composition.push_back(s/denom);
|
||||
m_totalThickness = thick;
|
||||
m_isValid = true;
|
||||
}
|
||||
|
||||
/*Calculates energy loss for travelling all the way through the target*/
|
||||
double Target::GetEnergyLossTotal(int zp, int ap, double startEnergy, double theta)
|
||||
{
|
||||
m_params.ZP = zp;
|
||||
m_params.massP = MassLookup::GetInstance().FindMass(zp, ap)*EnergyLoss::mev2u;
|
||||
|
||||
if(theta == M_PI/2.)
|
||||
return startEnergy;
|
||||
else if (theta > M_PI/2.)
|
||||
theta = M_PI - theta;
|
||||
|
||||
m_params.energy = startEnergy;
|
||||
m_params.thickness = m_totalThickness/(std::fabs(std::cos(theta)));
|
||||
|
||||
return EnergyLoss::GetEnergyLoss(m_params);
|
||||
}
|
||||
|
||||
/*Calculates the energy loss for traveling some fraction through the target*/
|
||||
double Target::GetEnergyLossFractionalDepth(int zp, int ap, double startEnergy, double theta, double percent_depth)
|
||||
{
|
||||
m_params.ZP = zp;
|
||||
m_params.massP = MassLookup::GetInstance().FindMass(zp, ap)*EnergyLoss::mev2u;
|
||||
|
||||
if(theta == M_PI/2.)
|
||||
return startEnergy;
|
||||
else if (theta > M_PI/2.)
|
||||
theta = M_PI-theta;
|
||||
|
||||
m_params.energy = startEnergy;
|
||||
m_params.thickness = m_totalThickness*percent_depth/(std::fabs(std::cos(theta)));
|
||||
|
||||
return EnergyLoss::GetEnergyLoss(m_params);
|
||||
}
|
||||
|
||||
/*Calculates reverse energy loss for travelling all the way through the target*/
|
||||
double Target::GetReverseEnergyLossTotal(int zp, int ap, double finalEnergy, double theta)
|
||||
{
|
||||
m_params.ZP = zp;
|
||||
m_params.massP = MassLookup::GetInstance().FindMass(zp, ap)*EnergyLoss::mev2u;
|
||||
|
||||
if(theta == M_PI/2.)
|
||||
return finalEnergy;
|
||||
else if (theta > M_PI/2.)
|
||||
theta = M_PI - theta;
|
||||
|
||||
m_params.energy = finalEnergy;
|
||||
m_params.thickness = m_totalThickness/(std::fabs(std::cos(theta)));
|
||||
|
||||
return EnergyLoss::GetReverseEnergyLoss(m_params);
|
||||
}
|
||||
|
||||
/*Calculates the reverse energy loss for traveling some fraction through the target*/
|
||||
double Target::GetReverseEnergyLossFractionalDepth(int zp, int ap, double finalEnergy, double theta, double percent_depth)
|
||||
{
|
||||
m_params.ZP = zp;
|
||||
m_params.massP = MassLookup::GetInstance().FindMass(zp, ap)*EnergyLoss::mev2u;
|
||||
|
||||
if(theta == M_PI/2.)
|
||||
return finalEnergy;
|
||||
else if (theta > M_PI/2.)
|
||||
theta = M_PI-theta;
|
||||
|
||||
m_params.energy = finalEnergy;
|
||||
m_params.thickness = m_totalThickness*percent_depth/(std::fabs(std::cos(theta)));
|
||||
|
||||
return EnergyLoss::GetReverseEnergyLoss(m_params);
|
||||
}
|
||||
|
||||
}
|
48
src/EnergyLoss/Target.h
Normal file
48
src/EnergyLoss/Target.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
|
||||
Target.h
|
||||
A basic target unit for use in the Mask environment. A target
|
||||
is defined as a single compound with elements Z,A of a given stoichiometry
|
||||
Holds an energy loss class
|
||||
|
||||
Based on code by D.W. Visser written at Yale for the original SPANC
|
||||
|
||||
Written by G.W. McCann Aug. 2020
|
||||
|
||||
*/
|
||||
#ifndef TARGET_H
|
||||
#define TARGET_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "EnergyLoss.h"
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
class Target
|
||||
{
|
||||
|
||||
public:
|
||||
Target();
|
||||
Target(const std::vector<int>& z, const std::vector<int>& stoich, double thick);
|
||||
~Target();
|
||||
|
||||
void SetParameters(const std::vector<int>& z, const std::vector<int>& stoich, double thick);
|
||||
double GetEnergyLossTotal(int zp, int ap, double startEnergy, double angle);
|
||||
double GetReverseEnergyLossTotal(int zp, int ap, double finalEnergy, double angle);
|
||||
double GetEnergyLossFractionalDepth(int zp, int ap, double startEnergy, double angle, double percent_depth);
|
||||
double GetReverseEnergyLossFractionalDepth(int zp, int ap, double finalEnergy, double angle, double percent_depth);
|
||||
|
||||
inline const EnergyLoss::Parameters& GetParameters() const { return m_params; }
|
||||
inline const double GetTotalThickness() const { return m_totalThickness; }
|
||||
inline const bool IsValid() { return m_isValid; }
|
||||
|
||||
private:
|
||||
EnergyLoss::Parameters m_params;
|
||||
double m_totalThickness;
|
||||
bool m_isValid;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
160
src/Histogrammer.cpp
Normal file
160
src/Histogrammer.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
#include "Histogrammer.h"
|
||||
#include "CalDict/DataStructs.h"
|
||||
#include <fstream>
|
||||
#include <TH1.h>
|
||||
#include <TH2.h>
|
||||
#include <TFile.h>
|
||||
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
Histogrammer::Histogrammer(const std::string& input) :
|
||||
m_inputData(""), m_outputData(""), m_eventPtr(new CalEvent), m_isValid(false)
|
||||
{
|
||||
TH1::AddDirectory(kFALSE);
|
||||
ParseConfig(input);
|
||||
}
|
||||
|
||||
Histogrammer::~Histogrammer() {}
|
||||
|
||||
void Histogrammer::ParseConfig(const std::string& name)
|
||||
{
|
||||
std::ifstream input(name);
|
||||
if(!input.is_open())
|
||||
{
|
||||
m_isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string junk;
|
||||
|
||||
double B, theta;
|
||||
std::vector<double> fpCal;
|
||||
|
||||
double thickness;
|
||||
std::vector<int> targ_z;
|
||||
std::vector<int> targ_s;
|
||||
|
||||
std::vector<ReconCut> cuts;
|
||||
ReconCut this_cut;
|
||||
|
||||
input>>junk;
|
||||
if(junk == "begin_data")
|
||||
{
|
||||
input>>junk>>m_inputData;
|
||||
input>>junk>>m_outputData;
|
||||
input>>junk;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
input>>junk;
|
||||
if(junk == "begin_reconstructor")
|
||||
{
|
||||
while(input>>junk)
|
||||
{
|
||||
if(junk == "begin_focalplane")
|
||||
{
|
||||
input>>junk>>B;
|
||||
input>>junk>>theta;
|
||||
input>>junk;
|
||||
if(junk == "begin_fpcal")
|
||||
{
|
||||
while(input>>junk)
|
||||
{
|
||||
if(junk == "end_fpcal")
|
||||
break;
|
||||
else
|
||||
fpCal.push_back(std::stod(junk));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(junk == "begin_target")
|
||||
{
|
||||
input>>junk>>thickness;
|
||||
input>>junk;
|
||||
if(junk == "begin_elements")
|
||||
{
|
||||
while(input>>junk)
|
||||
{
|
||||
if(junk == "end_elements")
|
||||
break;
|
||||
else
|
||||
{
|
||||
targ_z.push_back(std::stoi(junk));
|
||||
input>>junk;
|
||||
targ_s.push_back(std::stoi(junk));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(junk == "end_fpcal")
|
||||
continue;
|
||||
else if(junk == "end_target")
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
input>>junk;
|
||||
if(junk == "begin_cuts")
|
||||
{
|
||||
while(input>>junk)
|
||||
{
|
||||
if(junk == "end_cuts")
|
||||
break;
|
||||
else
|
||||
{
|
||||
this_cut.cutname = junk;
|
||||
input>>this_cut.filename;
|
||||
input>>this_cut.xparam;
|
||||
input>>this_cut.yparam;
|
||||
cuts.push_back(this_cut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//init resources
|
||||
Target target(targ_z, targ_s, thickness);
|
||||
m_recon.Init(target, theta, B, fpCal);
|
||||
m_cuts.InitCuts(cuts);
|
||||
m_cuts.InitEvent(m_eventPtr);
|
||||
|
||||
}
|
||||
|
||||
void Histogrammer::FillHistogram1D(const Histogram1DParams& params, double value)
|
||||
{
|
||||
auto h = std::static_pointer_cast<TH1>(m_histoMap[params.name]);
|
||||
if(h)
|
||||
h->Fill(value);
|
||||
else
|
||||
{
|
||||
h = std::make_shared<TH1F>(params.name.c_str(), params.title.c_str(), params.bins, params.min, params.max);
|
||||
h->Fill(value);
|
||||
m_histoMap[params.name] = h;
|
||||
}
|
||||
}
|
||||
|
||||
void Histogrammer::FillHistogram2D(const Histogram2DParams& params, double valueX, double valueY)
|
||||
{
|
||||
auto h = std::static_pointer_cast<TH2>(m_histoMap[params.name]);
|
||||
if(h)
|
||||
h->Fill(valueX, valueY);
|
||||
else
|
||||
{
|
||||
h = std::make_shared<TH2F>(params.name.c_str(), params.title.c_str(), params.binsX, params.minX, params.maxX, params.binsY, params.minY, params.maxY);
|
||||
h->Fill(valueX, valueY);
|
||||
m_histoMap[params.name] = h;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Histogrammer::Run()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
62
src/Histogrammer.h
Normal file
62
src/Histogrammer.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#ifndef HISTOGRAMMER_H
|
||||
#define HISTOGRAMMER_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <TROOT.h>
|
||||
#include "CutHandler.h"
|
||||
#include "Reconstructor.h"
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
struct Histogram1DParams
|
||||
{
|
||||
std::string name;
|
||||
std::string title;
|
||||
int bins;
|
||||
double min;
|
||||
double max;
|
||||
};
|
||||
|
||||
struct Histogram2DParams
|
||||
{
|
||||
std::string name;
|
||||
std::string title;
|
||||
int binsX;
|
||||
double minX;
|
||||
double maxX;
|
||||
int binsY;
|
||||
double minY;
|
||||
double maxY;
|
||||
};
|
||||
|
||||
class Histogrammer
|
||||
{
|
||||
public:
|
||||
Histogrammer(const std::string& input);
|
||||
~Histogrammer();
|
||||
|
||||
inline const bool IsValid() const { return m_isValid; }
|
||||
void Run();
|
||||
|
||||
private:
|
||||
void ParseConfig(const std::string& name);
|
||||
void FillHistogram1D(const Histogram1DParams& params, double value);
|
||||
void FillHistogram2D(const Histogram2DParams& params, double valueX, double valueY);
|
||||
|
||||
std::string m_inputData;
|
||||
std::string m_outputData;
|
||||
|
||||
CalEvent* m_eventPtr;
|
||||
|
||||
Reconstructor m_recon;
|
||||
CutHandler m_cuts;
|
||||
|
||||
bool m_isValid;
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<TObject>> m_histoMap;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
73
src/MassLookup.cpp
Normal file
73
src/MassLookup.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
|
||||
MassLookup.h
|
||||
Generates a map for isotopic masses using AMDC data; subtracts away
|
||||
electron mass from the atomic mass by default. Creates a static global instance
|
||||
of this map (MASS) for use throughout code it is included into.
|
||||
|
||||
Written by G.W. McCann Aug. 2020
|
||||
|
||||
*/
|
||||
#include "MassLookup.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
MassLookup* MassLookup::s_instance = new MassLookup();
|
||||
|
||||
MassLookup::MassLookup()
|
||||
{
|
||||
std::ifstream massfile("etc/mass.txt");
|
||||
if(massfile.is_open())
|
||||
{
|
||||
std::string junk, A, element;
|
||||
int Z;
|
||||
double atomicMassBig, atomicMassSmall, isotopicMass;
|
||||
getline(massfile,junk);
|
||||
getline(massfile,junk);
|
||||
while(massfile>>junk)
|
||||
{
|
||||
massfile>>Z>>A>>element>>atomicMassBig>>atomicMassSmall;
|
||||
isotopicMass = (atomicMassBig + atomicMassSmall*1e-6 - Z*electron_mass)*u_to_mev;
|
||||
std::string key = "("+std::to_string(Z)+","+A+")";
|
||||
massTable[key] = isotopicMass;
|
||||
elementTable[Z] = element;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr<<"ERR -- Unable to open mass file, check etc directory"<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
MassLookup::~MassLookup() {}
|
||||
|
||||
//Returns nuclear mass in MeV
|
||||
double MassLookup::FindMass(int Z, int A)
|
||||
{
|
||||
std::string key = "("+std::to_string(Z)+","+std::to_string(A)+")";
|
||||
auto data = massTable.find(key);
|
||||
if(data == massTable.end())
|
||||
{
|
||||
std::cerr<<"WARN -- Unable to find mass of (Z,A)=("<<Z<<","<<A<<")."<<std::endl;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return data->second;
|
||||
}
|
||||
|
||||
//returns element symbol
|
||||
std::string MassLookup::FindSymbol(int Z, int A)
|
||||
{
|
||||
auto data = elementTable.find(Z);
|
||||
if(data == elementTable.end())
|
||||
{
|
||||
std::cerr<<"WARN -- Unable to find symbol of (Z,A)=("<<Z<<","<<A<<")."<<std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string fullsymbol = std::to_string(A) + data->second;
|
||||
return fullsymbol;
|
||||
}
|
||||
|
||||
}
|
44
src/MassLookup.h
Normal file
44
src/MassLookup.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
|
||||
MassLookup.h
|
||||
Generates a map for isotopic masses using AMDC data; subtracts away
|
||||
electron mass from the atomic mass by default. Creates a static global instance
|
||||
of this map (MASS) for use throughout code it is included into.
|
||||
|
||||
Written by G.W. McCann Aug. 2020
|
||||
|
||||
Converted to true singleton to simplify usage -- Aug. 2021 GWM
|
||||
*/
|
||||
#ifndef MASS_LOOKUP_H
|
||||
#define MASS_LOOKUP_H
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
class MassLookup
|
||||
{
|
||||
public:
|
||||
MassLookup();
|
||||
~MassLookup();
|
||||
double FindMass(int Z, int A);
|
||||
std::string FindSymbol(int Z, int A);
|
||||
|
||||
inline static MassLookup& GetInstance() { return *s_instance; }
|
||||
|
||||
private:
|
||||
static MassLookup* s_instance;
|
||||
std::unordered_map<std::string, double> massTable;
|
||||
std::unordered_map<int, std::string> elementTable;
|
||||
|
||||
//constants
|
||||
static constexpr double u_to_mev = 931.4940954;
|
||||
static constexpr double electron_mass = 0.000548579909;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
12
src/RandomGenerator.cpp
Normal file
12
src/RandomGenerator.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include "RandomGenerator.h"
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
RandomGenerator::RandomGenerator()
|
||||
{
|
||||
std::random_device rd;
|
||||
rng.seed(rd());
|
||||
}
|
||||
|
||||
RandomGenerator::~RandomGenerator() {}
|
||||
}
|
28
src/RandomGenerator.h
Normal file
28
src/RandomGenerator.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef RANDOMGENERATOR_H
|
||||
#define RANDOMGENERATOR_H
|
||||
|
||||
#include <random>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
class RandomGenerator {
|
||||
public:
|
||||
RandomGenerator();
|
||||
~RandomGenerator();
|
||||
|
||||
inline std::mt19937& GetGenerator() { return rng; }
|
||||
inline static RandomGenerator& GetInstance()
|
||||
{
|
||||
static RandomGenerator s_generator;
|
||||
return s_generator;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mt19937 rng;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
332
src/Reconstructor.cpp
Normal file
332
src/Reconstructor.cpp
Normal file
|
@ -0,0 +1,332 @@
|
|||
#include "Reconstructor.h"
|
||||
#include "MassLookup.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
constexpr double Reconstructor::s_phiDet[5]; //C++11 weirdness with static constexpr
|
||||
|
||||
Reconstructor::Reconstructor()
|
||||
{
|
||||
}
|
||||
|
||||
Reconstructor::Reconstructor(const Target& target, double spsTheta, double spsB, const std::vector<double>& spsCal)
|
||||
{
|
||||
Init(target, spsTheta, spsB, spsCal);
|
||||
}
|
||||
|
||||
Reconstructor::~Reconstructor() {}
|
||||
|
||||
void Reconstructor::Init(const Target& target, double spsTheta, double spsB, const std::vector<double>& spsCal)
|
||||
{
|
||||
m_target = target;
|
||||
m_focalPlane.Init({spsB, spsTheta, spsCal});
|
||||
for(int i=0; i<5; i++)
|
||||
m_sabreArray.emplace_back(SabreDetector::Parameters(s_phiDet[i], s_tiltAngle, s_zOffset, false, i));
|
||||
}
|
||||
|
||||
TLorentzVector Reconstructor::GetSabre4Vector(const SabrePair& pair, double mass)
|
||||
{
|
||||
TVector3 coords;
|
||||
TLorentzVector result;
|
||||
double p, E;
|
||||
if(pair.detID == 4)
|
||||
coords = m_sabreArray[4].GetHitCoordinates(15-pair.local_ring, pair.local_wedge);
|
||||
else
|
||||
coords = m_sabreArray[pair.detID].GetHitCoordinates(pair.local_ring, pair.local_wedge);
|
||||
p = std::sqrt(pair.ringE*(pair.ringE + 2.0*mass));
|
||||
E = pair.ringE + mass;
|
||||
result.SetPxPyPzE(p*std::sin(coords.Theta())*std::cos(coords.Phi()),
|
||||
p*std::sin(coords.Theta())*std::sin(coords.Phi()),
|
||||
p*std::cos(coords.Theta()),
|
||||
E);
|
||||
return result;
|
||||
}
|
||||
|
||||
TLorentzVector Reconstructor::GetSabre4VectorEloss(const SabrePair& pair, double mass, const NucID& id)
|
||||
{
|
||||
TVector3 coords;
|
||||
TLorentzVector result;
|
||||
double p, E, rxnKE;
|
||||
if(pair.detID == 4)
|
||||
coords = m_sabreArray[4].GetHitCoordinates(15-pair.local_ring, pair.local_wedge);
|
||||
else
|
||||
coords = m_sabreArray[pair.detID].GetHitCoordinates(pair.local_ring, pair.local_wedge);
|
||||
rxnKE = pair.ringE + m_target.GetReverseEnergyLossFractionalDepth(id.Z, id.A, pair.ringE, coords.Theta(), 0.5);
|
||||
p = std::sqrt(pair.ringE*(pair.ringE + 2.0*mass));
|
||||
E = pair.ringE + mass;
|
||||
result.SetPxPyPzE(p*std::sin(coords.Theta())*std::cos(coords.Phi()),
|
||||
p*std::sin(coords.Theta())*std::sin(coords.Phi()),
|
||||
p*std::cos(coords.Theta()),
|
||||
E);
|
||||
return result;
|
||||
}
|
||||
|
||||
TLorentzVector Reconstructor::GetFP4VectorEloss(double xavg, double mass, const NucID& id)
|
||||
{
|
||||
TLorentzVector result;
|
||||
double p = m_focalPlane.GetP(xavg, id.Z);
|
||||
double theta = m_focalPlane.GetFPTheta();
|
||||
double KE = std::sqrt(p*p + mass*mass) - mass;
|
||||
double rxnKE = KE + m_target.GetReverseEnergyLossFractionalDepth(id.Z, id.A, KE, theta, 0.5);
|
||||
double rxnP = sqrt(rxnKE*(rxnKE + 2.0*mass));
|
||||
double rxnE = rxnKE + mass;
|
||||
result.SetPxPyPzE(rxnP*std::sin(theta), 0.0, rxnP*std::cos(theta), rxnE);
|
||||
return result;
|
||||
}
|
||||
|
||||
TLorentzVector Reconstructor::GetProj4VectorEloss(double beamKE, double mass, const NucID& id)
|
||||
{
|
||||
TLorentzVector result;
|
||||
double rxnKE = beamKE + m_target.GetReverseEnergyLossFractionalDepth(id.Z, id.A, beamKE, 0.0, 0.5);
|
||||
result.SetPxPyPzE(0.0,0.0,std::sqrt(rxnKE*(rxnKE+2.0*mass)),rxnKE+mass);
|
||||
return result;
|
||||
}
|
||||
|
||||
ReconResult Reconstructor::RunThreeParticleExcitation(const SabrePair& p1, const SabrePair& p2, const SabrePair& p3, const std::vector<NucID>& nuclei)
|
||||
{
|
||||
ReconResult result;
|
||||
|
||||
NucID parent;
|
||||
parent.Z = nuclei[0].Z + nuclei[1].Z + nuclei[2].Z;
|
||||
parent.A = nuclei[0].A + nuclei[1].A + nuclei[2].A;
|
||||
|
||||
if(parent.Z > parent.A || parent.A <= 0 || parent.Z < 0)
|
||||
{
|
||||
std::cerr<<"Invalid parent nucleus at Reconstructor::RunThreeParticleExcitation with Z: "<<parent.Z<<" A: "<<parent.A<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
MassLookup& masses = MassLookup::GetInstance();
|
||||
double massParent = masses.FindMass(parent.Z, parent.A);
|
||||
double massP1 = masses.FindMass(nuclei[0].Z, nuclei[0].A);
|
||||
double massP2 = masses.FindMass(nuclei[1].Z, nuclei[1].A);
|
||||
double massP3 = masses.FindMass(nuclei[2].Z, nuclei[2].A);
|
||||
|
||||
if(massParent == 0.0 || massP1 == 0.0 || massP2 == 0.0 || massP3 == 0.0)
|
||||
{
|
||||
std::cerr<<"Invalid nuclei at Reconstructor::RunThreeParticleExcitation by mass!"<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
auto p1_vec = GetSabre4VectorEloss(p1, massP1, nuclei[0]);
|
||||
auto p2_vec = GetSabre4VectorEloss(p2, massP2, nuclei[1]);
|
||||
auto p3_vec = GetSabre4VectorEloss(p3, massP3, nuclei[2]);
|
||||
|
||||
auto parent_vec = p1_vec + p2_vec + p3_vec;
|
||||
|
||||
result.excitation = parent_vec.M() - massParent;
|
||||
return result;
|
||||
}
|
||||
|
||||
ReconResult Reconstructor::RunTwoParticleExcitation(const SabrePair& p1, const SabrePair& p2, const std::vector<NucID>& nuclei)
|
||||
{
|
||||
ReconResult result;
|
||||
|
||||
NucID parent;
|
||||
parent.Z = nuclei[0].Z + nuclei[1].Z;
|
||||
parent.A = nuclei[0].A + nuclei[1].A;
|
||||
|
||||
if(parent.Z > parent.A || parent.A <= 0 || parent.Z < 0)
|
||||
{
|
||||
std::cerr<<"Invalid parent nucleus at Reconstructor::RunTwoParticleExcitation with Z: "<<parent.Z<<" A: "<<parent.A<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
MassLookup& masses = MassLookup::GetInstance();
|
||||
double massParent = masses.FindMass(parent.Z, parent.A);
|
||||
double massP1 = masses.FindMass(nuclei[0].Z, nuclei[0].A);
|
||||
double massP2 = masses.FindMass(nuclei[1].Z, nuclei[1].A);
|
||||
|
||||
if(massParent == 0.0 || massP1 == 0.0 || massP2 == 0.0)
|
||||
{
|
||||
std::cerr<<"Invalid nuclei at Reconstructor::RunTwoParticleExcitation by mass!"<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
auto p1_vec = GetSabre4VectorEloss(p1, massP1, nuclei[0]);
|
||||
auto p2_vec = GetSabre4VectorEloss(p2, massP2, nuclei[1]);
|
||||
|
||||
auto parent_vec = p1_vec + p2_vec;
|
||||
|
||||
result.excitation = parent_vec.M() - massParent;
|
||||
return result;
|
||||
}
|
||||
|
||||
ReconResult Reconstructor::RunFPResidExcitation(double xavg, double beamKE, const std::vector<NucID>& nuclei)
|
||||
{
|
||||
ReconResult result;
|
||||
|
||||
NucID resid;
|
||||
resid.Z = nuclei[0].Z + nuclei[1].Z - nuclei[2].Z;
|
||||
resid.A = nuclei[0].A + nuclei[1].A - nuclei[2].A;
|
||||
|
||||
if(resid.Z > resid.A || resid.A <= 0 || resid.Z < 0)
|
||||
{
|
||||
std::cerr<<"Invalid reisdual nucleus at Reconstructor::RunFPResidExcitation with Z: "<<resid.Z<<" A: "<<resid.A<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
MassLookup& masses = MassLookup::GetInstance();
|
||||
double massTarg = masses.FindMass(nuclei[0].Z, nuclei[0].A);
|
||||
double massProj = masses.FindMass(nuclei[1].Z, nuclei[1].A);
|
||||
double massEject = masses.FindMass(nuclei[2].Z, nuclei[2].A);
|
||||
double massResid = masses.FindMass(resid.Z, resid.A);
|
||||
|
||||
if(massTarg == 0.0 || massProj == 0.0 || massEject == 0.0 || massResid == 0.0)
|
||||
{
|
||||
std::cerr<<"Invalid nuclei at Reconstructor::RunFPResidExcitation by mass!"<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
TLorentzVector targ_vec;
|
||||
targ_vec.SetPxPyPzE(0.0, 0.0, 0.0, massTarg);
|
||||
auto proj_vec = GetProj4VectorEloss(beamKE, massProj, nuclei[1]);
|
||||
auto eject_vec = GetFP4VectorEloss(xavg, massEject, nuclei[2]);
|
||||
|
||||
auto resid_vec = targ_vec + proj_vec - eject_vec;
|
||||
|
||||
result.excitation = resid_vec.M() - massResid;
|
||||
|
||||
auto parent_vec = targ_vec + proj_vec;
|
||||
auto boost = parent_vec.BoostVector();
|
||||
eject_vec.Boost(-1.0*boost);
|
||||
result.theta_cm = eject_vec.Theta();
|
||||
result.phi_cm = eject_vec.Phi();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ReconResult Reconstructor::RunSabreResidExcitationDetEject(double beamKE, const SabrePair& pair, const std::vector<NucID>& nuclei)
|
||||
{
|
||||
ReconResult result;
|
||||
|
||||
NucID resid;
|
||||
resid.Z = nuclei[0].Z + nuclei[1].Z - nuclei[2].Z;
|
||||
resid.A = nuclei[0].A + nuclei[1].A - nuclei[2].A;
|
||||
|
||||
if(resid.Z > resid.A || resid.A <= 0 || resid.Z < 0)
|
||||
{
|
||||
std::cerr<<"Invalid reisdual nucleus at Reconstructor::RunFPResidExcitation with Z: "<<resid.Z<<" A: "<<resid.A<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
MassLookup& masses = MassLookup::GetInstance();
|
||||
double massTarg = masses.FindMass(nuclei[0].Z, nuclei[0].A);
|
||||
double massProj = masses.FindMass(nuclei[1].Z, nuclei[1].A);
|
||||
double massEject = masses.FindMass(nuclei[2].Z, nuclei[2].A);
|
||||
double massResid = masses.FindMass(resid.Z, resid.A);
|
||||
|
||||
if(massTarg == 0.0 || massProj == 0.0 || massEject == 0.0 || massResid == 0.0)
|
||||
{
|
||||
std::cerr<<"Invalid nuclei at Reconstructor::RunFPResidExcitation by mass!"<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
TLorentzVector targ_vec;
|
||||
targ_vec.SetPxPyPzE(0.0, 0.0, 0.0, massTarg);
|
||||
auto proj_vec = GetProj4VectorEloss(beamKE, massProj, nuclei[1]);
|
||||
auto eject_vec = GetSabre4VectorEloss(pair, massEject, nuclei[2]);
|
||||
|
||||
auto resid_vec = targ_vec + proj_vec - eject_vec;
|
||||
|
||||
result.excitation = resid_vec.M() - massResid;
|
||||
|
||||
auto parent_vec = targ_vec + proj_vec;
|
||||
auto boost = parent_vec.BoostVector();
|
||||
eject_vec.Boost(-1.0*boost);
|
||||
result.theta_cm = eject_vec.Theta();
|
||||
result.phi_cm = eject_vec.Phi();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ReconResult Reconstructor::RunSabreExcitation(double xavg, double beamKE, const SabrePair& sabre, const std::vector<NucID>& nuclei)
|
||||
{
|
||||
ReconResult result;
|
||||
|
||||
NucID decayFrag;
|
||||
decayFrag.Z = nuclei[0].Z + nuclei[1].Z - nuclei[2].Z - nuclei[3].Z;
|
||||
decayFrag.A = nuclei[0].A + nuclei[1].A - nuclei[2].A - nuclei[3].A;
|
||||
|
||||
if(decayFrag.Z > decayFrag.A || decayFrag.A <= 0 || decayFrag.Z < 0)
|
||||
{
|
||||
std::cerr<<"Invalid reisdual nucleus at Reconstructor::RunSabreExcitation with Z: "<<decayFrag.Z<<" A: "<<decayFrag.A<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
MassLookup& masses = MassLookup::GetInstance();
|
||||
double massTarg = masses.FindMass(nuclei[0].Z, nuclei[0].A);
|
||||
double massProj = masses.FindMass(nuclei[1].Z, nuclei[1].A);
|
||||
double massEject = masses.FindMass(nuclei[2].Z, nuclei[2].A);
|
||||
double massDecayBreak = masses.FindMass(nuclei[3].Z, nuclei[3].A);
|
||||
double massDecayFrag = masses.FindMass(decayFrag.Z, decayFrag.A);
|
||||
|
||||
if(massTarg == 0.0 || massProj == 0.0 || massEject == 0.0 || massDecayBreak == 0.0 || massDecayFrag == 0.0)
|
||||
{
|
||||
std::cerr<<"Invalid nuclei at Reconstructor::RunSabreExcitation by mass!"<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
TLorentzVector targ_vec;
|
||||
targ_vec.SetPxPyPzE(0.0, 0.0, 0.0, massTarg);
|
||||
auto proj_vec = GetProj4VectorEloss(beamKE, massProj, nuclei[1]);
|
||||
auto eject_vec = GetFP4VectorEloss(xavg, massEject, nuclei[2]);
|
||||
auto decayBreak_vec = GetSabre4VectorEloss(sabre, massDecayBreak, nuclei[3]);
|
||||
TLorentzVector resid_vec = targ_vec + proj_vec - eject_vec;
|
||||
TLorentzVector decayFrag_vec = resid_vec - decayBreak_vec;
|
||||
|
||||
result.excitation = decayFrag_vec.M() - massDecayFrag;
|
||||
auto boost = resid_vec.BoostVector();
|
||||
decayBreak_vec.Boost(-1.0*boost);
|
||||
result.theta_cm = decayBreak_vec.Theta();
|
||||
result.phi_cm = decayBreak_vec.Phi();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ReconResult Reconstructor::RunSabreExcitationDetEject(double xavg, double beamKE, const SabrePair& sabre, const std::vector<NucID>& nuclei)
|
||||
{
|
||||
ReconResult result;
|
||||
|
||||
NucID decayFrag;
|
||||
decayFrag.Z = nuclei[0].Z + nuclei[1].Z - nuclei[2].Z - nuclei[3].Z;
|
||||
decayFrag.A = nuclei[0].A + nuclei[1].A - nuclei[2].A - nuclei[3].A;
|
||||
|
||||
if(decayFrag.Z > decayFrag.A || decayFrag.A <= 0 || decayFrag.Z < 0)
|
||||
{
|
||||
std::cerr<<"Invalid reisdual nucleus at Reconstructor::RunSabreExcitation with Z: "<<decayFrag.Z<<" A: "<<decayFrag.A<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
MassLookup& masses = MassLookup::GetInstance();
|
||||
double massTarg = masses.FindMass(nuclei[0].Z, nuclei[0].A);
|
||||
double massProj = masses.FindMass(nuclei[1].Z, nuclei[1].A);
|
||||
double massEject = masses.FindMass(nuclei[2].Z, nuclei[2].A);
|
||||
double massDecayBreak = masses.FindMass(nuclei[3].Z, nuclei[3].A);
|
||||
double massDecayFrag = masses.FindMass(decayFrag.Z, decayFrag.A);
|
||||
|
||||
if(massTarg == 0.0 || massProj == 0.0 || massEject == 0.0 || massDecayBreak == 0.0 || massDecayFrag == 0.0)
|
||||
{
|
||||
std::cerr<<"Invalid nuclei at Reconstructor::RunSabreExcitation by mass!"<<std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
TLorentzVector targ_vec;
|
||||
targ_vec.SetPxPyPzE(0.0, 0.0, 0.0, massTarg);
|
||||
auto proj_vec = GetProj4VectorEloss(beamKE, massProj, nuclei[1]);
|
||||
auto decayBreak_vec = GetFP4VectorEloss(xavg, massEject, nuclei[2]);
|
||||
auto eject_vec = GetSabre4VectorEloss(sabre, massDecayBreak, nuclei[3]);
|
||||
TLorentzVector resid_vec = targ_vec + proj_vec - eject_vec;
|
||||
TLorentzVector decayFrag_vec = resid_vec - decayBreak_vec;
|
||||
|
||||
result.excitation = decayFrag_vec.M() - massDecayFrag;
|
||||
auto boost = resid_vec.BoostVector();
|
||||
decayBreak_vec.Boost(-1.0*boost);
|
||||
result.theta_cm = decayBreak_vec.Theta();
|
||||
result.phi_cm = decayBreak_vec.Phi();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
77
src/Reconstructor.h
Normal file
77
src/Reconstructor.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
#ifndef RECONSTRUCTOR_H
|
||||
#define RECONSTRUCTOR_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "EnergyLoss/Target.h"
|
||||
#include "CalDict/DataStructs.h"
|
||||
#include "TLorentzVector.h"
|
||||
#include "Detectors/SabreDetector.h"
|
||||
#include "Detectors/FocalPlaneDetector.h"
|
||||
|
||||
namespace SabreRecon {
|
||||
|
||||
struct ReconResult
|
||||
{
|
||||
double excitation;
|
||||
double theta_cm;
|
||||
double phi_cm;
|
||||
};
|
||||
|
||||
struct NucID
|
||||
{
|
||||
int Z, A;
|
||||
|
||||
NucID() :
|
||||
Z(0), A(0)
|
||||
{
|
||||
}
|
||||
|
||||
NucID(int z, int a) :
|
||||
Z(z), A(a)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class Reconstructor
|
||||
{
|
||||
public:
|
||||
Reconstructor();
|
||||
Reconstructor(const Target& target, double spsTheta, double spsB, const std::vector<double>& spsCal);
|
||||
~Reconstructor();
|
||||
|
||||
void Init(const Target& target, double spsTheta, double spsB, const std::vector<double>& spsCal);
|
||||
|
||||
ReconResult RunThreeParticleExcitation(const SabrePair& p1, const SabrePair& p2, const SabrePair& p3, const std::vector<NucID>& nuclei);
|
||||
ReconResult RunTwoParticleExcitation(const SabrePair& p1, const SabrePair& p2, const std::vector<NucID>& nuclei);
|
||||
//nuclei: target, projectile, ejectile
|
||||
ReconResult RunFPResidExcitation(double xavg, double beamKE, const std::vector<NucID>& nuclei);
|
||||
//nuclei: target, projectile, ejectile
|
||||
ReconResult RunSabreResidExcitationDetEject(double beamKE, const SabrePair& sabre, const std::vector<NucID>& nuclei);
|
||||
//nuclei: target, projectile, ejectile, decaySabre
|
||||
ReconResult RunSabreExcitation(double xavg, double beamKE, const SabrePair& sabre, const std::vector<NucID>& nuclei);
|
||||
//nuclei: target, projectile, ejectile, decayFP
|
||||
ReconResult RunSabreExcitationDetEject(double xavg, double beamKE, const SabrePair& sabre, const std::vector<NucID>& nuclei);
|
||||
|
||||
|
||||
private:
|
||||
TLorentzVector GetSabre4Vector(const SabrePair& pair, double mass);
|
||||
TLorentzVector GetSabre4VectorEloss(const SabrePair& pair, double mass, const NucID& id);
|
||||
TLorentzVector GetFP4VectorEloss(double xavg, double mass, const NucID& id);
|
||||
TLorentzVector GetProj4VectorEloss(double beamKE, double mass, const NucID& id);
|
||||
|
||||
std::vector<SabreDetector> m_sabreArray;
|
||||
FocalPlaneDetector m_focalPlane;
|
||||
Target m_target;
|
||||
|
||||
//SABRE constants
|
||||
static constexpr double s_phiDet[5] = { 306.0, 18.0, 234.0, 162.0, 90.0 };
|
||||
static constexpr double s_tiltAngle = 40.0;
|
||||
static constexpr double s_zOffset = -0.1245;
|
||||
|
||||
//Kinematics constants
|
||||
static constexpr double s_deg2rad = M_PI/180.0; //rad/deg
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
26
src/main.cpp
Normal file
26
src/main.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include "Histogrammer.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
if(argc != 2)
|
||||
{
|
||||
std::cerr<<"SabreRecon requires an input config file! Unable to run."<<std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
SabreRecon::Histogrammer grammer(argv[1]);
|
||||
|
||||
if(grammer.IsValid())
|
||||
grammer.Run();
|
||||
else
|
||||
{
|
||||
std::cerr<<"Config file error! Shutting down."<<std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user