1
0
Fork 0
mirror of https://github.com/gwm17/SabreRecon.git synced 2024-11-22 18:28:51 -05:00

First commit

This commit is contained in:
Gordon McCann 2022-05-24 13:12:53 -04:00
commit 3e4074051c
32 changed files with 5258 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
*.o
*.so
*.sublime-project
*.sublime-workspace
*.cxx
*.pcm
SabreRecon
!.gitignore

140
CalDict.make Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

26
include/DataStructs.h Normal file
View 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
View 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

View 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
View 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"

View File

@ -0,0 +1,3 @@
#include "DataStructs.h"
bool EnforceDictionaryLinked() { return true; }

26
src/CalDict/DataStructs.h Normal file
View 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

View File

@ -0,0 +1,6 @@
#ifdef __ROOTCLING__
#pragma link C++ struct SabrePair+;
#pragma link C++ struct CalEvent+;
#endif

103
src/CutHandler.cpp Normal file
View 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
View 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

View 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;
}
}

View 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

View 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);
}
}

View 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

View 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.
}
}
}

View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}