280 lines
8.9 KiB
C++
280 lines
8.9 KiB
C++
#include "HitOutputManager.hh"
|
|
|
|
#include "TFile.h"
|
|
#include "TH1D.h"
|
|
#include "TH2D.h"
|
|
#include "TTree.h"
|
|
|
|
#include <cstring>
|
|
#include <iomanip>
|
|
|
|
namespace {
|
|
const char* kRootOutputName = ANASENG4_DATA_DIR "/hits.root";
|
|
const char* kTextOutputName = ANASENG4_DATA_DIR "/hits.txt";
|
|
}
|
|
|
|
HitOutputManager& HitOutputManager::Instance()
|
|
{
|
|
static HitOutputManager instance;
|
|
return instance;
|
|
}
|
|
|
|
HitOutputManager::HitOutputManager()
|
|
: fRootFile(nullptr),
|
|
fTree(nullptr),
|
|
fEventId(0),
|
|
fDetectorId(0),
|
|
fAnodeId(-1),
|
|
fCathodeId(-1),
|
|
fKineticEnergy(0.0),
|
|
fEnergyDeposit(0.0),
|
|
fWireDeltaESinTheta(0.0),
|
|
fAnodeEnergy(0.0),
|
|
fCathodeEnergy(0.0),
|
|
fWireDeltaE(0.0),
|
|
fX(0.0),
|
|
fY(0.0),
|
|
fZ(0.0),
|
|
fVertexX(0.0),
|
|
fVertexY(0.0),
|
|
fVertexZ(0.0),
|
|
fKineticEnergyHist(nullptr),
|
|
fEnergyDepositHist(nullptr),
|
|
fWireDeltaEHist(nullptr),
|
|
fWireDeltaESinThetaVsDetEHist(nullptr),
|
|
fHitZHist(nullptr),
|
|
fVertexZHist(nullptr),
|
|
fDetectorIdHist(nullptr),
|
|
fHitXYHist(nullptr),
|
|
fVertexXYHist(nullptr),
|
|
fIncludeElectrons(true)
|
|
{
|
|
ResetBuffers();
|
|
}
|
|
|
|
HitOutputManager::~HitOutputManager()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
void HitOutputManager::Open()
|
|
{
|
|
Close();
|
|
|
|
fRootFile = TFile::Open(kRootOutputName, "RECREATE");
|
|
fTree = new TTree("hits", "Sensitive detector hits");
|
|
fTree->Branch("eventID", &fEventId, "eventID/I");
|
|
fTree->Branch("particleType", fParticleType, "particleType/C");
|
|
fTree->Branch("kineticEnergy", &fKineticEnergy, "kineticEnergy/D");
|
|
fTree->Branch("energyDeposit", &fEnergyDeposit, "energyDeposit/D");
|
|
fTree->Branch("wireDeltaESinTheta", &fWireDeltaESinTheta, "wireDeltaESinTheta/D");
|
|
fTree->Branch("detectorType", fDetectorType, "detectorType/C");
|
|
fTree->Branch("detectorID", &fDetectorId, "detectorID/I");
|
|
fTree->Branch("anodeID", &fAnodeId, "anodeID/I");
|
|
fTree->Branch("cathodeID", &fCathodeId, "cathodeID/I");
|
|
fTree->Branch("anodeEnergy", &fAnodeEnergy, "anodeEnergy/D");
|
|
fTree->Branch("cathodeEnergy", &fCathodeEnergy, "cathodeEnergy/D");
|
|
fTree->Branch("wireDeltaE", &fWireDeltaE, "wireDeltaE/D");
|
|
fTree->Branch("volumeName", fVolumeName, "volumeName/C");
|
|
fTree->Branch("x", &fX, "x/D");
|
|
fTree->Branch("y", &fY, "y/D");
|
|
fTree->Branch("z", &fZ, "z/D");
|
|
fTree->Branch("vertexX", &fVertexX, "vertexX/D");
|
|
fTree->Branch("vertexY", &fVertexY, "vertexY/D");
|
|
fTree->Branch("vertexZ", &fVertexZ, "vertexZ/D");
|
|
|
|
fKineticEnergyHist = new TH1D("hKineticEnergy", "Hit kinetic energy;Kinetic energy [MeV];Counts", 200, 0.0, 200.0);
|
|
fEnergyDepositHist = new TH1D("hEnergyDeposit", "Step energy deposit;Energy deposit [MeV];Counts", 200, 0.0, 50.0);
|
|
fWireDeltaEHist = new TH1D("hWireDeltaE", "Energy loss between anode and cathode crossings;#DeltaE [MeV];Counts", 200, 0.0, 20.0);
|
|
fWireDeltaESinThetaVsDetEHist =
|
|
new TH2D("hWireDeltaESinThetaVsDetE",
|
|
"PC #DeltaE #times sin(#theta_{z}) vs detector deposited energy;Detector deposited energy [MeV];#DeltaE_{PC} #times sin(#theta_{z}) [MeV]",
|
|
200,
|
|
0.0,
|
|
14.0,
|
|
200,
|
|
0.0,
|
|
20.0);
|
|
fHitZHist = new TH1D("hHitZ", "Hit z position;z [mm];Counts", 200, -200.0, 200.0);
|
|
fVertexZHist = new TH1D("hVertexZ", "Track vertex z position;z_{vertex} [mm];Counts", 200, -250.0, 250.0);
|
|
fDetectorIdHist = new TH1D("hDetectorID", "Detector ID occupancy;Detector ID;Counts", 64, -0.5, 63.5);
|
|
fHitXYHist = new TH2D("hHitXY", "Hit position;x [mm];y [mm]", 200, -200.0, 200.0, 200, -200.0, 200.0);
|
|
fVertexXYHist = new TH2D("hVertexXY", "Track vertex position;x_{vertex} [mm];y_{vertex} [mm]", 200, -200.0, 200.0, 200, -200.0, 200.0);
|
|
|
|
fTextFile.open(kTextOutputName, std::ios::out | std::ios::trunc);
|
|
fTextFile << "eventID,particleType,kineticEnergy,energyDeposit,wireDeltaESinTheta,detectorType,detectorID,anodeID,cathodeID,anodeEnergy,cathodeEnergy,wireDeltaE,volumeName,x,y,z,vertexX,vertexY,vertexZ\n";
|
|
}
|
|
|
|
void HitOutputManager::Close()
|
|
{
|
|
if (fRootFile != nullptr) {
|
|
fRootFile->cd();
|
|
if (fTree != nullptr) {
|
|
fTree->Write("", TObject::kOverwrite);
|
|
}
|
|
if (fKineticEnergyHist != nullptr) {
|
|
fKineticEnergyHist->Write("", TObject::kOverwrite);
|
|
}
|
|
if (fEnergyDepositHist != nullptr) {
|
|
fEnergyDepositHist->Write("", TObject::kOverwrite);
|
|
}
|
|
if (fWireDeltaEHist != nullptr) {
|
|
fWireDeltaEHist->Write("", TObject::kOverwrite);
|
|
}
|
|
if (fWireDeltaESinThetaVsDetEHist != nullptr) {
|
|
fWireDeltaESinThetaVsDetEHist->Write("", TObject::kOverwrite);
|
|
}
|
|
if (fHitZHist != nullptr) {
|
|
fHitZHist->Write("", TObject::kOverwrite);
|
|
}
|
|
if (fVertexZHist != nullptr) {
|
|
fVertexZHist->Write("", TObject::kOverwrite);
|
|
}
|
|
if (fDetectorIdHist != nullptr) {
|
|
fDetectorIdHist->Write("", TObject::kOverwrite);
|
|
}
|
|
if (fHitXYHist != nullptr) {
|
|
fHitXYHist->Write("", TObject::kOverwrite);
|
|
}
|
|
if (fVertexXYHist != nullptr) {
|
|
fVertexXYHist->Write("", TObject::kOverwrite);
|
|
}
|
|
fRootFile->Close();
|
|
delete fRootFile;
|
|
fRootFile = nullptr;
|
|
fTree = nullptr;
|
|
fKineticEnergyHist = nullptr;
|
|
fEnergyDepositHist = nullptr;
|
|
fWireDeltaEHist = nullptr;
|
|
fWireDeltaESinThetaVsDetEHist = nullptr;
|
|
fHitZHist = nullptr;
|
|
fVertexZHist = nullptr;
|
|
fDetectorIdHist = nullptr;
|
|
fHitXYHist = nullptr;
|
|
fVertexXYHist = nullptr;
|
|
}
|
|
|
|
if (fTextFile.is_open()) {
|
|
fTextFile.close();
|
|
}
|
|
}
|
|
|
|
void HitOutputManager::SetIncludeElectrons(bool includeElectrons)
|
|
{
|
|
fIncludeElectrons = includeElectrons;
|
|
}
|
|
|
|
bool HitOutputManager::GetIncludeElectrons() const
|
|
{
|
|
return fIncludeElectrons;
|
|
}
|
|
|
|
bool HitOutputManager::ShouldRecordParticle(const std::string& particleType) const
|
|
{
|
|
if (fIncludeElectrons) {
|
|
return true;
|
|
}
|
|
|
|
return particleType != "e-" && particleType != "e+";
|
|
}
|
|
|
|
void HitOutputManager::RecordHit(int eventId,
|
|
const std::string& particleType,
|
|
double kineticEnergy,
|
|
double energyDeposit,
|
|
double wireDeltaESinTheta,
|
|
const std::string& detectorType,
|
|
int detectorId,
|
|
int anodeId,
|
|
int cathodeId,
|
|
double anodeEnergy,
|
|
double cathodeEnergy,
|
|
double wireDeltaE,
|
|
const std::string& volumeName,
|
|
const G4ThreeVector& position,
|
|
const G4ThreeVector& vertexPosition)
|
|
{
|
|
if (fRootFile == nullptr || fTree == nullptr || !fTextFile.is_open()) {
|
|
return;
|
|
}
|
|
|
|
ResetBuffers();
|
|
|
|
fEventId = eventId;
|
|
fDetectorId = detectorId;
|
|
fAnodeId = anodeId;
|
|
fCathodeId = cathodeId;
|
|
fKineticEnergy = kineticEnergy;
|
|
fEnergyDeposit = energyDeposit;
|
|
fWireDeltaESinTheta = wireDeltaESinTheta;
|
|
fAnodeEnergy = anodeEnergy;
|
|
fCathodeEnergy = cathodeEnergy;
|
|
fWireDeltaE = wireDeltaE;
|
|
fX = position.x();
|
|
fY = position.y();
|
|
fZ = position.z();
|
|
fVertexX = vertexPosition.x();
|
|
fVertexY = vertexPosition.y();
|
|
fVertexZ = vertexPosition.z();
|
|
|
|
std::strncpy(fParticleType, particleType.c_str(), sizeof(fParticleType) - 1);
|
|
std::strncpy(fDetectorType, detectorType.c_str(), sizeof(fDetectorType) - 1);
|
|
std::strncpy(fVolumeName, volumeName.c_str(), sizeof(fVolumeName) - 1);
|
|
|
|
fTree->Fill();
|
|
if (fKineticEnergyHist != nullptr) {
|
|
fKineticEnergyHist->Fill(fKineticEnergy);
|
|
}
|
|
if (fEnergyDepositHist != nullptr) {
|
|
fEnergyDepositHist->Fill(fEnergyDeposit);
|
|
}
|
|
if (fWireDeltaEHist != nullptr && fAnodeId >= 0 && fCathodeId >= 0) {
|
|
fWireDeltaEHist->Fill(fWireDeltaE);
|
|
}
|
|
if (fWireDeltaESinThetaVsDetEHist != nullptr && fAnodeId >= 0 && fCathodeId >= 0) {
|
|
fWireDeltaESinThetaVsDetEHist->Fill(fEnergyDeposit, 100.0 * fWireDeltaESinTheta); //2D histogram programmed
|
|
}
|
|
if (fHitZHist != nullptr) {
|
|
fHitZHist->Fill(fZ);
|
|
}
|
|
if (fVertexZHist != nullptr) {
|
|
fVertexZHist->Fill(fVertexZ);
|
|
}
|
|
if (fDetectorIdHist != nullptr) {
|
|
fDetectorIdHist->Fill(fDetectorId);
|
|
}
|
|
if (fHitXYHist != nullptr) {
|
|
fHitXYHist->Fill(fX, fY);
|
|
}
|
|
if (fVertexXYHist != nullptr) {
|
|
fVertexXYHist->Fill(fVertexX, fVertexY);
|
|
}
|
|
|
|
fTextFile << fEventId << ','
|
|
<< fParticleType << ','
|
|
<< std::setprecision(12) << fKineticEnergy << ','
|
|
<< fEnergyDeposit << ','
|
|
<< fWireDeltaESinTheta << ','
|
|
<< fDetectorType << ','
|
|
<< fDetectorId << ','
|
|
<< fAnodeId << ','
|
|
<< fCathodeId << ','
|
|
<< fAnodeEnergy << ','
|
|
<< fCathodeEnergy << ','
|
|
<< fWireDeltaE << ','
|
|
<< fVolumeName << ','
|
|
<< fX << ','
|
|
<< fY << ','
|
|
<< fZ << ','
|
|
<< fVertexX << ','
|
|
<< fVertexY << ','
|
|
<< fVertexZ << '\n';
|
|
}
|
|
|
|
void HitOutputManager::ResetBuffers()
|
|
{
|
|
fParticleType[0] = '\0';
|
|
fDetectorType[0] = '\0';
|
|
fVolumeName[0] = '\0';
|
|
}
|