First commit

This commit is contained in:
Gordon McCann 2021-07-14 11:54:17 -04:00
commit 3111a61991
56 changed files with 2799 additions and 0 deletions

22
.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
###directories to ignore###
./rootfiles/
./pics/
./images/
./hotfixes/
###file types to ignore###
*.swp
*.o
*.cxx
*.root
*.bin
*.pcm
*.jpg
*.png
*.sublime-project
*.sublime-workspace
event_log.txt
.DS_Store
###include this###
!.gitignore

41
README.md Normal file
View File

@ -0,0 +1,41 @@
# Event Builder Skeleton
This is a program designed to be a launching point for event building data from CAEN digitizers run using CoMPASS software. It reads in raw binary data and converts it into time ordered events and saves the data to a ROOT file. This code is intended to provide a start point; further changes would need to be made to make a code that provides some preliminary analysis of the data.
This code can in princple work with any setup that uses CAEN digitizers, as it requires no knowledge of the physical setup other than a coincidence window. It can also be used to build waveform data (THIS HAS NOT BEEN FULLY TESTED).
## GWMEVB vs. GWMEVB_CL
There are two programs provided. They are `GWMEVB` and `GWMEVB_CL`. The first is a full GUI version of the event builder. The GUI supports all conversion methods and the plotting tool. The second is a commandline version.
### Building Events
The event building operation is the bulk of the analysis process. As files are being converted to ROOT from the raw CoMPASS binary, events are built using information given by the user. In particular the code asks the user to specify a workspace (a top level directory which contains the following sub directories: raw_binary, temp_binary, raw_root, sorted), a shift file, a scaler file, a coincidence window, and the size of the file buffer in number of hits.
The buffer size is used to specify the size of the buffer in number of hits (each file has its own buffer of the specified size). The file evaluates the size of a hit by checking the first event and determining how many waveform samples are present. NOTE: The assumption is that a base event (no waveform samples) is 24 bytes (i.e. board, channel, timestamp, long, short, flags, Nsamples). If you run with the calibrated enrgy option in CoMPASS this appends an extra word in the data and will cause a crash if it is run through the event builder without modification!
#### Types of Event Building
1. SlowSort: Full event building. Data is read from the binary files, time ordered, and then grouped into events based on the coincidence window.
2. Convert: Takes raw binary data and converts it into time-ordered root data.
#### Slow Sorting
The first stage is slow sorting the shifted data by timestamp and orgainizing detector hits into
large data events. Events are structures which contain all detector hits that occur within a given coincidence window with physical detector variables. This event data is then written to an output file.
All of the user input is handled through an input file in the program directory named
`input.txt`. This file is preformated; all the user needs to do is update the names and
values. Everything from input and output directories, to shifts and coincidence windows should
be specified in this file. Note that directorires should be explicit fullpaths.
### Merging
The program is capable of merging several root files together using either `hadd` or the ROOT TChain class. Currently, only the TChain version is implemented in the API, however if you want the other method, it does exist in the RunCollector class.
### Scaler Support
Currently the pipeline supports declaring individual digitizer channels as scalers. These channels will be used a pure counting measures. To make a channel a scaler, put the CoMPASS formated name of the channel and board (check the given etc/ScalerFile.txt for an example) in a text file along with a parameter name for the scaler to be saved as. These files are then processed outside of the event building loop, which can greatly increase the computational speed. Future versions will include scaler rates as well.
## System Requirements
Only tested with `ROOT` 6.14, mileage may vary
Uses C++11 standards
Only compatible with MacOSX and Linux
## Compliling and Running
To compile use the command `make`
To clean run `make clean` and then run `make`
For a complete rebuild use `make clean_header` as well as `make clean`.

4
bin/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
###use this to keep the directory but not any of the contents###
*
!archivist
!.gitignore

15
bin/archivist Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
RUNNO=$1
BINARYDIR=/nvme/27Al_Feb2021/DAQ/run_$RUNNO/UNFILTERED/
ARCHIVE=/nvme/WorkingData/raw_binary/run_$RUNNO.tar.gz
echo "Running archivist for binary data in $BINARYDIR to archive $ARCHIVE..."
cd $BINARYDIR
tar -cvzf $ARCHIVE ./*.bin
cd -
echo "Complete."

93
etc/Plotter.C Normal file
View File

@ -0,0 +1,93 @@
#include <TROOT.h>
#include <TCanvas.h>
#include <TFile.h>
#include <TCutG.h>
#include <TTree.h>
#include <iostream>
#include "include/DataStructs.h"
R__LOAD_LIBRARY(lib/libSPSDict.dylib)
void Plotter() {
TFile* input = TFile::Open("/Volumes/LaCie/9BMarch2020/combined/main_data_carbonCal.root","READ");
TTree* intree = (TTree*) input->Get("SPSTree");
TFile *cutfile = TFile::Open("/Volumes/LaCie/9BMarch2020/maindata_12C_extraTheta.root","READ");
TCutG *cut = (TCutG*) cutfile->Get("CUTG");
cut->SetName("extraTheta");
cut->SetLineColor(kRed);
cut->SetVarX("xavg");
cut->SetVarY("theta");
ProcessedEvent *event_address = new ProcessedEvent();
intree->SetBranchAddress("event", &event_address);
TFile *outfile = TFile::Open("/Volumes/LaCie/9BMarch2020/9b_histograms/carbonCal_thetaGating.root","RECREATE");
TH2F *xtheta = new TH2F("xtheta","xtheta",600,-300,300,300,0,1.75);
TH2F *xde = new TH2F("xde","xde",600,-300,300,512,0,4096);
TH2F *xde_thetaCut = new TH2F("xde_thetaCut","xde_thetaCut",600,-300,300,512,0,4096);
xde_thetaCut->SetLineColor(kRed);
xde_thetaCut->SetMarkerColor(kRed);
TH2F *xde_antithetaCut = new TH2F("xde_antithetaCut","xde_antithetaCut",600,-300,300,512,0,4096);
xde_antithetaCut->SetLineColor(kBlack);
xde_antithetaCut->SetMarkerColor(kBlue);
TH1F *anodeRelTime = new TH1F("anodeRelTime","anodeRelTime",1000,-1000,1000);
TH1F *anodeRelTime_thetaCut = new TH1F("anodeRelTime_thetaCut","anodeRelTime_thetacut",1000,-1000,1000);
anodeRelTime_thetaCut->SetLineColor(kRed);
TH1F *anodeRelTime_antithetaCut = new TH1F("anodeRelTime_antithetaCut","anodeRelTime_antithetacut",1000,-1000,1000);
anodeRelTime_antithetaCut->SetLineColor(kBlack);
std::cout<<"Total number of Entries: "<<intree->GetEntries()<<std::endl;
for(ULong64_t i=0; i<intree->GetEntries(); i++) {
std::cout<<"\rNumber of events processed: "<<i<<std::flush;
intree->GetEntry(i);
double anodeRT = event_address->anodeBackTime - event_address->scintLeftTime;
if(anodeRT != 0) {
xtheta->Fill(event_address->xavg, event_address->theta);
xde->Fill(event_address->xavg, event_address->delayBackRightE);
anodeRelTime->Fill(anodeRT);
if(cut->IsInside(event_address->xavg, event_address->theta)) {
xde_thetaCut->Fill(event_address->xavg, event_address->delayBackRightE);
anodeRelTime_thetaCut->Fill(anodeRT);
} else {
xde_antithetaCut->Fill(event_address->xavg, event_address->delayBackRightE);
anodeRelTime_antithetaCut->Fill(anodeRT);
}
}
}
TCanvas *c1 = new TCanvas();
c1->Divide(2,2);
c1->cd(1);
xde->Draw("colz");
c1->cd(2);
xde_antithetaCut->Draw();
xde_thetaCut->Draw("same");
c1->BuildLegend();
c1->cd(3);
anodeRelTime->Draw();
anodeRelTime_antithetaCut->Draw("same");
anodeRelTime_thetaCut->Draw("same");
c1->BuildLegend();
c1->cd(4);
xtheta->Draw();
cut->Draw("same");
input->Close();
cutfile->Close();
outfile->cd();
xtheta->Write();
xde->Write();
xde_thetaCut->Write();
xde_antithetaCut->Write();
anodeRelTime->Write();
anodeRelTime_thetaCut->Write();
anodeRelTime_antithetaCut->Write();
c1->Write();
c1->Close();
outfile->Close();
}

133
etc/SabreSingles.C Normal file
View File

@ -0,0 +1,133 @@
#include <TROOT.h>
#include <TFile.h>
#include <TTree.h>
#include <TH1.h>
#include <THashTable.h>
#include <iostream>
#include <string>
#include <unordered_map>
#include "include/DataStructs.h"
#include "include/CompassHit.h"
#include "include/GainMatcher.h"
#include "include/SabreMap.h"
R__LOAD_LIBRARY(lib/libGainMatcher.dylib)
R__LOAD_LIBRARY(lib/libSPSDict.dylib)
R__LOAD_LIBRARY(lib/libSabreMap.dylib)
void MyFill(THashTable *table, std::string name, int bins, double min, double max, double value) {
TH1F *histo = (TH1F*) table->FindObject(name.c_str());
if(histo == NULL) {
TH1F* h = new TH1F(name.c_str(), name.c_str(), bins, min, max);
h->Fill(value);
table->Add(h);
} else {
histo->Fill(value);
}
}
void MyFill(THashTable *table, std::string name, int binsx, double minx, double maxx, double valuex
, int binsy, double miny, double maxy, double valuey) {
TH2F *histo = (TH2F*) table->FindObject(name.c_str());
if(histo == NULL) {
TH2F* h = new TH2F(name.c_str(), name.c_str(), binsx, minx, maxx, binsy, miny, maxy);
h->Fill(valuex, valuey);
table->Add(h);
} else {
histo->Fill(valuex, valuey);
}
}
void SabreSingles_raw() {
GainMatcher gains;
gains.SetFile("etc/March2020_gainmatch_2.0V_5486Am241.txt");
std::unordered_map<int, sabrechan> smap;
FillSabreMap("etc/ChannelMap_March2020_flipping.dat", smap);
TFile *input = TFile::Open("/Volumes/LaCie/9BMarch2020/raw_root_singles/compass_run_37.root", "READ");
TTree *intree = (TTree*) input->Get("Data");
ULong64_t ts;
UShort_t e, c, b, es;
UInt_t f;
intree->SetBranchAddress("Timestamp", &ts);
intree->SetBranchAddress("Channel", &c);
intree->SetBranchAddress("Board", &b);
intree->SetBranchAddress("Energy", &e);
intree->SetBranchAddress("EnergyShort", &es);
intree->SetBranchAddress("Flags", &f);
intree->SetMaxVirtualSize(4000000000);
TFile *output = TFile::Open("/Volumes/LaCie/9BMarch2020/analyzed_singles/singles_run37.root","RECREATE");
THashTable *hash = new THashTable();
int gchan;
DPPChannel hit;
cout<<"Total Number of Entries: "<<intree->GetEntries()<<endl;
for(ULong64_t i=0; i<intree->GetEntries(); i++) {
intree->GetEntry(i);
std::cout<<"\rNumber of entries processed: "<<i<<std::flush;
hit.Timestamp = ts;
hit.Energy = e;
hit.Channel = c;
hit.Board = b;
hit.EnergyShort = es;
hit.Flags = f;
gchan = hit.Channel + hit.Board*16;
sabrechan& schan = smap[gchan];
if(schan.side_pos.first == "RING" && hit.Energy>20) {
MyFill(hash, Form("detector%i_ring%i_energy",schan.detID,hit.Channel), 280, 0, 28, hit.Energy*gains.GetScaler(gchan));
}
}
input->Close();
hash->Write();
output->Close();
}
void SabreSingles_analyzed() {
std::unordered_map<int, sabrechan> smap;
FillSabreMap("etc/ChannelMap_March2020_flipping.dat", smap);
TFile *input = TFile::Open("/Volumes/LaCie/9BMarch2020/combined/downscaled_singles.root", "READ");
TTree *intree = (TTree*) input->Get("SPSTree");
ProcessedEvent *event_address = new ProcessedEvent();
intree->SetBranchAddress("event", &event_address);
intree->SetMaxVirtualSize(4000000000);
TFile *output = TFile::Open("/Volumes/LaCie/9BMarch2020/analyzed_singles/downscale_histograms.root", "RECREATE");
THashTable *hash = new THashTable();
std::cout<<"Total entries: "<<intree->GetEntries()<<std::endl;
for(ULong64_t i=0; i<intree->GetEntries(); i++) {
std::cout<<"\rNumber of entries processed: "<<i<<std::flush;
intree->GetEntry(i);
for(int j=0; j<5; j++) {
for(unsigned int k=0; k<(event_address->sabreArray[j].rings.size()); k++) {
MyFill(hash, Form("detector%i_ring%i_energy",j,event_address->sabreArray[j].rings[k].Ch), 280,0,28, event_address->sabreArray[j].rings[k].Long);
}
}
}
input->Close();
hash->Write();
output->Close();
delete event_address;
}
void SabreSingles() {
//SabreSingles_raw();
SabreSingles_analyzed();
}

3
etc/ScalerFile.txt Normal file
View File

@ -0,0 +1,3 @@
Format: scaler_param_name assoc_binary_file_name_without_runID
NOTE: As of this version, scalers are pure counting parameters (the total events will be counted and saved as a TParameter with the data)
Data_CH5@V1730_89 beamint

View File

@ -0,0 +1,5 @@
Format: scaler_param_name assoc_binary_file_name_without_runID
NOTE: As of this version, scalers are pure counting parameters (the total events will be counted and saved as a TParameter with the data)
CH0@V1730_89_Data t1
CH1@V1730_89_Data t2

View File

@ -0,0 +1,12 @@
Format: board channel/keyword shift
NOTE: Do not delete these lines! If no shift is specified for a channel, no shift is applied. Use keyword 'all' to apply a uniform shift to all channels in a single board. Shifts are in ps.
0 all 110000
1 all 70000
2 all 70000
3 all -115000
4 all 185000
5 all 195000
6 all 225000
7 all 235000
8 0 650000
8 1 650000

View File

@ -0,0 +1,12 @@
Format: board channel/keyword shift
NOTE: Do not delete these lines! If no shift is specified for a channel, no shift is applied. Use keyword 'all' to apply a uniform shift to all channels in a single board. Shifts are in ps.
0 all 260000
1 all 220000
2 all 220000
3 all 335000
4 all 385000
5 all 395000
6 all 425000
7 all 435000
8 0 900000
8 1 900000

View File

@ -0,0 +1,4 @@
Format: board channel/keyword shift
NOTE: Do not delete these lines! If no shift is specified for a channel, no shift is applied. Use keyword 'all' to apply a uniform shift to all channels in a single board. Shifts are in ps.
0 0 685000
0 1 685000

11
etc/logo.txt Normal file
View File

@ -0,0 +1,11 @@
_
| |
| |
___ _ __ ___ ___ ____ _| |__ _ _______
/ __|| ' \/ __|/ __| / __ ` | _ \| '__/ __ \
\__ \| |\ \__ \\__ \| | | | | | | | | |__| |
__) | |/ /__) |__) | |__| | |_| | | | ___/
|___/| .__/|___/____/ \____,_|____/|_| \____|
| |
| |
|_|

View File

@ -0,0 +1,3 @@
Format: scaler_param_name assoc_binary_file_name_without_runID
NOTE: As of this version, scalers are pure counting parameters (the total events will be counted and saved as a TParameter with the data)
CH5@V1730_89_Data beamint

View File

@ -0,0 +1,12 @@
Format: board channel/keyword shift
NOTE: Do not delete these lines! If no shift is specified for a channel, no shift is applied. Use keyword 'all' to apply a uniform shift to all channels in a single board. Shifts are in ps.
0 all 110000
1 all 70000
2 all 70000
3 all 135000
4 all 185000
5 all 195000
6 all 225000
7 all 235000
8 0 650000
8 1 650000

2
example/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
###Keep this dir###
!.gitignore

Binary file not shown.

2
example/raw_binary/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
###Keep this dir###
!.gitignore

Binary file not shown.

2
example/raw_root/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
###Keep this dir###
!.gitignore

2
example/sorted/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
###Keep this dir###
!.gitignore

2
example/temp_binary/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
###Keep this dir###
!.gitignore

5
include/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
###ignore pch###
*.gch
###include this###
!.gitignore

67
include/CompassFile.h Normal file
View File

@ -0,0 +1,67 @@
/*
CompassFile.h
Wrapper class around a shared pointer to an ifstream. Here the shared pointer is used
to overcome limitations of the ifstream class, namely that it is written such that ifstream
cannot be modified by move semantics. Contains all information needed to parse a single binary
CompassFile. Currently has a class wide defined buffer size; may want to make this user input
in the future.
Written by G.W. McCann Oct. 2020
*/
#ifndef COMPASSFILE_H
#define COMPASSFILE_H
#include "CompassHit.h"
#include "ShiftMap.h"
#include <memory>
class CompassFile {
public:
CompassFile();
CompassFile(const std::string& filename);
CompassFile(const std::string& filename, unsigned int bsize);
~CompassFile();
void Open(const std::string& filename);
void Close();
inline bool IsOpen() { return m_file->is_open(); };
bool GetNextHit();
inline CompassHit GetCurrentHit() const { return m_currentHit; };
inline std::string GetName() { return m_filename; };
inline bool CheckHitHasBeenUsed() { return hitUsedFlag; }; //query to find out if we've used the current hit
inline void SetHitHasBeenUsed() { hitUsedFlag = true; }; //flip the flag to indicate the current hit has been used
inline bool IsEOF() { return eofFlag; }; //see if we've read all available data
inline bool* GetUsedFlagPtr() { return &hitUsedFlag; };
inline void AttachShiftMap(ShiftMap* map) { m_smap = map; };
inline unsigned int GetSize() { return m_size; };
inline unsigned int GetNumberOfHits() { return m_nHits; };
private:
unsigned int GetHitSize();
void ParseNextHit();
void GetNextBuffer();
using Buffer = std::vector<char>;
using FilePointer = std::shared_ptr<std::ifstream>; //to make this class copy/movable
std::string m_filename;
Buffer hitBuffer;
char* bufferIter;
char* bufferEnd;
ShiftMap* m_smap; //NOT owned by CompassFile. DO NOT delete
bool hitUsedFlag;
unsigned int bufsize = 200000; //size of the buffer in hits
unsigned int hitsize = 24; //size of a CompassHit in bytes (without alignment padding)
unsigned int m_buffersize;
CompassHit m_currentHit;
FilePointer m_file;
bool eofFlag;
unsigned int m_size; //size of the file in bytes
unsigned int m_nHits; //number of hits in the file (m_size/24)
};
#endif

15
include/CompassHit.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef COMPASS_HIT_H
#define COMPASS_HIT_H
struct CompassHit {
UShort_t board = 400;
UShort_t channel = 400;
ULong64_t timestamp = 0;
UShort_t lgate = 0;
UShort_t sgate = 0;
UInt_t flags = 0;
UInt_t Ns = 0;
std::vector<Int_t> samples;
};
#endif

64
include/CompassRun.h Normal file
View File

@ -0,0 +1,64 @@
/*
CompassRun.h
Class designed as abstraction of a collection of binary files that represent the total data in a single
Compass data run. It handles the user input (shift maps, file collection etc.) and creates a list of
CompassFiles from which to draw data. It then draws data from these files, organizes them in time,
and writes to a ROOT file for further processing.
Written by G.W. McCann Oct. 2020
*/
#ifndef COMPASSRUN_H
#define COMPASSRUN_H
#include "CompassFile.h"
#include "DataStructs.h"
#include "RunCollector.h"
#include "ShiftMap.h"
#include <TParameter.h>
#include <TGProgressBar.h>
#include <TSystem.h>
class CompassRun {
public:
CompassRun();
CompassRun(const std::string& dir, unsigned int bsize);
~CompassRun();
inline void SetDirectory(const std::string& dir) { directory = dir; };
inline void SetScalerInput(const std::string& filename) { m_scalerinput = filename; };
inline void SetRunNumber(int n) { runNum = n; };
inline void SetShiftMap(const std::string& filename) { m_smap.SetFile(filename); };
void Convert2RawRoot(const std::string& name);
void Convert2SortedRoot(const std::string& name, double window);
inline void AttachProgressBar(TGProgressBar* pb) { m_pb = pb; };
private:
bool GetBinaryFiles();
bool GetHitsFromFiles();
void SetScalers();
void ReadScalerData(const std::string& filename);
void SetProgressBar();
std::string directory, m_scalerinput;
std::vector<CompassFile> m_datafiles;
unsigned int startIndex; //this is the file we start looking at; increases as we finish files.
ShiftMap m_smap;
std::unordered_map<std::string, TParameter<Long64_t>> m_scaler_map; //maps scaler files to the TParameter to be saved
//Potential branch variables
CompassHit hit;
std::vector<DPPChannel> event;
//what run is this
int runNum;
unsigned int m_totalHits;
unsigned int m_buffersize;
//Scaler switch
bool m_scaler_flag;
//GUI progress bar, if attached
TGProgressBar* m_pb;
};
#endif

18
include/DataStructs.h Normal file
View File

@ -0,0 +1,18 @@
/*DataStructs.h
*Data structures for analysis. To be implemented as a dictionary for ROOT in LinkDef
*Based on: FocalPlane_SABRE.h
*Gordon M. Oct. 2019
*/
#ifndef DATA_STRUCTS_H
#define DATA_STRUCTS_H
using namespace std;
struct DPPChannel {
Double_t Timestamp;
Int_t Channel, Board, Energy, EnergyShort;
Int_t Flags;
vector<Int_t> Samples;
};
#endif

80
include/EVBMainFrame.h Normal file
View File

@ -0,0 +1,80 @@
#ifndef EVBMAINFRAME_H
#define EVBMAINFRAME_H
#include <TGClient.h>
#include <TGWindow.h>
#include <TGFrame.h>
#include <TGNumberEntry.h>
#include <TGTextEntry.h>
#include <TGButton.h>
#include <TGMenu.h>
#include <TGTextViewStream.h>
#include <TGProgressBar.h>
#include <TTimer.h>
#include <TGComboBox.h>
#include "GWMEventBuilder.h"
class EVBMainFrame : public TGMainFrame {
public:
EVBMainFrame(const TGWindow* p, UInt_t w, UInt_t h);
virtual ~EVBMainFrame();
void CloseWindow();
void HandleMenuSelection(int id);
void DoOpenWorkdir();
void DoOpenSMapfile();
void DoOpenScalerfile();
void DoRun();
void HandleTypeSelection(int box, int entry);
bool SetParameters();
void DisplayWorkdir(const char* dir);
void DisplaySMap(const char* file);
void DisplayScaler(const char* file);
void SaveConfig(const char* file);
void LoadConfig(const char* file);
void UpdateWorkdir();
void UpdateSMap();
void UpdateScaler();
void RunMerge(const char* dir, const char* file);
void DisableAllInput();
void EnableAllInput();
enum WidgetId {
WORKDIR,
SMAP,
SCALER,
SLOWWIND,
BUFSIZE,
TYPEBOX,
RMIN,
RMAX,
M_LOAD_CONFIG,
M_SAVE_CONFIG,
M_EXIT
};
ClassDef(EVBMainFrame, 0);
private:
TGTextButton *fRunButton, *fOpenWorkButton, *fOpenSMapButton, *fOpenScalerButton;
TGTextEntry *fWorkField;
TGTextEntry * fSMapField;
TGTextEntry *fScalerField;
TGComboBox *fTypeBox;
TGNumberEntryField *fSlowWindowField, *fBufferSizeField;
TGNumberEntryField *fRMinField, *fRMaxField;
TGHProgressBar* fProgressBar;
TGPopupMenu *fFileMenu;
GWMEventBuilder fBuilder;
int counter;
UInt_t MAIN_W, MAIN_H;
};
#endif

28
include/EventBuilder.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef EVENTBUILDER_H
#define EVENTBUILDER_H
//STD Library
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <stdexcept>
#include <fstream>
#include <iomanip>
//ROOT
#include <TROOT.h>
#include <TFile.h>
#include <TChain.h>
#include <TTree.h>
#include <TString.h>
#include <TMath.h>
#include <TH1.h>
#include <TH2.h>
#include <TCanvas.h>
#include <THashTable.h>
#include <TCutG.h>
#endif

46
include/FileViewFrame.h Normal file
View File

@ -0,0 +1,46 @@
/*
FileViewFrame.h
Wrapper class on a TGTransientFrame (temporary frame assoc. with a main frame)
Designed to graphically display directories and files for selection. Takes in a type
to specify the signal pathing.
Written by G.W. McCann Sep. 2020
*/
#ifndef FILEVIEWFRAME_H
#define FILEVIEWFRAME_H
#include "EVBMainFrame.h"
#include <TGTextEntry.h>
#include <TGFSContainer.h>
#include <TGListView.h>
#include <TQObject.h>
#include <RQ_OBJECT.h>
class FileViewFrame {
RQ_OBJECT("FileViewFrame"); //ROOT wrapping into the gui environment
public:
FileViewFrame(const TGWindow* p, const TGFrame* main, UInt_t w, UInt_t h, EVBMainFrame *parent, int type);
virtual ~FileViewFrame();
void CloseWindow();
void DoOk();
void DoCancel();
void DoDoubleClick(TGLVEntry* entry, int id);
void DisplayDir(const TString& name);
void SendText(const char* text); // *SIGNAL*
ClassDef(FileViewFrame, 0); //ROOT requirement
private:
TGTransientFrame *fMain;
TGTextButton *fOkButton, *fCancelButton;
TGTextEntry *fNameField;
TGFileContainer *fContents;
TGListView *fViewer;
std::string suffix;
bool dirFlag;
};
#endif

59
include/FlagHandler.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef FLAGHANDLER_H
#define FLAGHANDLER_H
#include <map>
struct FlagCount {
long total_counts=0;
long dead_time=0;
long time_roll=0;
long time_reset=0;
long fake_event=0;
long mem_full=0;
long trig_lost=0;
long n_trig_lost=0;
long sat_in_gate=0;
long trig_1024=0;
long sat_input=0;
long n_trig_count=0;
long event_not_matched=0;
long fine_time=0;
long pile_up=0;
long pll_lock_loss=0;
long over_temp=0;
long adc_shutdown=0;
};
class FlagHandler {
public:
FlagHandler();
FlagHandler(const std::string& filename);
~FlagHandler();
void CheckFlag(int board, int channel, int flag);
const int DEAD_TIME = 0x00000001;
const int TIME_ROLLOVER = 0x00000002;
const int TIME_RESET = 0x00000004;
const int FAKE_EVENT = 0x00000008;
const int MEM_FULL = 0x00000010;
const int TRIG_LOST = 0x00000020;
const int N_TRIG_LOST = 0x00000040;
const int SATURATING_IN_GATE = 0x00000080;
const int TRIG_1024_COUNTED = 0x00000100;
const int SATURATING_INPUT = 0x00000400;
const int N_TRIG_COUNTED = 0x00000800;
const int EVENT_NOT_MATCHED = 0x00001000;
const int FINE_TIME = 0x00004000;
const int PILE_UP = 0x00008000;
const int PLL_LOCK_LOSS = 0x00080000;
const int OVER_TEMP = 0x00100000;
const int ADC_SHUTDOWN = 0x00200000;
private:
std::ofstream log;
std::map<int, FlagCount> event_count_map;
void WriteLog();
};
#endif

72
include/GWMEventBuilder.h Normal file
View File

@ -0,0 +1,72 @@
/*
GWMEventBuilder.h
Class which represents the API of the event building environment. Wraps together the core concepts
of the event builder, from conversion to plotting. Even intended to be able to archive data.
Currently under development.
Written by G.W. McCann Oct. 2020
*/
#ifndef GWMEVENTBUILDER_H
#define GWMEVENTBUILDER_H
#include "RunCollector.h"
#include <TGProgressBar.h>
class GWMEventBuilder {
public:
GWMEventBuilder();
~GWMEventBuilder();
bool ReadConfigFile(const std::string& filename);
void WriteConfigFile(const std::string& filename);
void MergeROOTFiles();
void Convert2SortedRoot();
void Convert2RawRoot();
inline void SetAnalysisType(int type) { m_analysisType = type;};
inline int GetAnalysisType() { return m_analysisType; };
inline void SetRunRange(int rmin, int rmax) { m_rmin = rmin; m_rmax = rmax; };
inline void SetWorkDirectory(const std::string& fullpath) { m_workspace = fullpath; };
inline void SetBoardShiftFile(const std::string& name) { m_shiftfile = name; };
inline void SetScalerFile(const std::string& name) { m_scalerfile = name; };
inline void SetSlowCoincidenceWindow(double window) { m_SlowWindow = window; };
inline void SetBufferSize(unsigned int size) { m_buffersize = size; };
inline int GetRunMin() {return m_rmin;};
inline int GetRunMax() {return m_rmax;};
inline std::string GetWorkDirectory() {return m_workspace;};
inline double GetSlowCoincidenceWindow() { return m_SlowWindow; };
inline std::string GetBoardShiftFile() { return m_shiftfile; };
inline std::string GetScalerFile() { return m_scalerfile; };
inline unsigned int GetBufferSize() { return m_buffersize; };
inline void AttachProgressBar(TGProgressBar* pb) { m_pb = pb; };
enum BuildType {
CONVERT,
CONVERT_S,
MERGE
};
private:
int m_rmin, m_rmax;
std::string m_workspace;
std::string m_shiftfile;
std::string m_scalerfile;
double m_SlowWindow;
int m_analysisType;
unsigned int m_buffersize;
RunCollector grabber;
TGProgressBar* m_pb;
};
#endif

7
include/LinkDef_Gui.h Normal file
View File

@ -0,0 +1,7 @@
#ifdef __CLING__
#pragma link C++ class EVBMainFrame+;
#pragma link C++ class FileViewFrame+;
#endif

7
include/LinkDef_evb.h Normal file
View File

@ -0,0 +1,7 @@
#ifdef __CLING__
#pragma link C++ struct DPPChannel+;
#pragma link C++ class std::vector<DPPChannel>+;
#pragma link C++ class std::vector<int>+;
#endif

18
include/OrderChecker.h Normal file
View File

@ -0,0 +1,18 @@
/*
OrderChecker.h
Very simple class designed to test whether or not a root file is time ordered.
Meant to be used with newly converted from binary data. Only for development.
Written by G.W. McCann Oct. 2020
*/
#ifndef ORDERCHECKER_H
#define ORDERCHECKER_H
class OrderChecker {
public:
OrderChecker();
~OrderChecker();
bool IsOrdered(const std::string& filename);
};
#endif

50
include/RunCollector.h Normal file
View File

@ -0,0 +1,50 @@
/*RunCollector.h
*Class that searches through a directory looking for files of a specified format.
*Stores all filenames in a vector which can be accessed by other functions/classes for
*further use. Can also use Merge() to combine all files using hadd into a single file.
*Merge() is NOT RECOMMENDED in the analyzer program.
*
*Created Jan2020 by GWM
*/
#ifndef RUNCOLLECTOR_H
#define RUNCOLLECTOR_H
#include <TSystemDirectory.h>
#include <TSystemFile.h>
#include <TCollection.h>
#include <TList.h>
#include <cstdlib>
#include <cstdio>
using namespace std;
class RunCollector {
public:
RunCollector();
RunCollector(const string& dirname, const string& prefix, const string& suffix);
RunCollector(const string& dirname, const string& prefix, const string& suffix, int min, int max);
~RunCollector();
void SetSearchParams(const string& dirname, const string& prefix, const string& suffix, int min, int max);
int Merge_hadd(const string& outname);
int Merge_TChain(const string& outname);
int GrabAllFiles();
int GrabFilesInRange();
std::string GrabFile(int runNum);
inline std::string GetSearchDir() {return dir.Data();};
inline std::string GetSearchPrefix() {return run.Data();};
inline std::string GetSearchSuffix() {return end.Data();};
inline int GetRunMin() {return MinRun;};
inline int GetRunMax() {return MaxRun;};
vector<TString> filelist;
private:
bool initFlag;
TString dir;
TString run;
TString end;
Int_t MaxRun, MinRun; //user run limits
const Int_t LITERALMAX = 1000; //class run limit
};
#endif

35
include/ShiftMap.h Normal file
View File

@ -0,0 +1,35 @@
/*
ShiftMap.h
New class to act a go-between for timestamp shifts to channels. Takes in a
formated file containing data for shifts and then stores them in an unordered_map.
Key is a global compass channel (board#*16 + channel). Shifts in ps.
Note: Timestamps are now shifted in binary conversion. This means that shifts *MUST*
be stored as Long64_t types. No decimals!
Written by G.W. McCann Oct. 2020
*/
#ifndef SHIFTMAP_H
#define SHIFTMAP_H
class ShiftMap {
public:
ShiftMap();
ShiftMap(const std::string& filename);
~ShiftMap();
void SetFile(const std::string& filename);
inline bool IsSet() { return is_set; };
inline std::string GetFilename() { return m_filename; };
Long64_t GetShift(int gchan);
private:
void ParseFile();
std::string m_filename;
bool is_set;
std::unordered_map<int, Long64_t> m_map;
};
#endif

50
include/SlowSort.h Normal file
View File

@ -0,0 +1,50 @@
/*SlowSort.h
*Class designed to first time-order raw data, and then based on a given coincidence window
*sort the raw data into coincidence structures. Utilizes dictionary elements DPPChannel and
*CoincEvent. Based on work by S. Balak, K. Macon, and E. Good from LSU.
*
*Gordon M. Oct. 2019
*
*Refurbished and updated Jan 2020 GWM
*/
#ifndef SLOW_SORT_H
#define SLOW_SORT_H
#include "CompassHit.h"
#include "DataStructs.h"
#include <TH2.h>
using namespace std;
class SlowSort {
public:
SlowSort();
SlowSort(double windowSize);
~SlowSort();
inline void SetWindowSize(double window) { coincWindow = window; };
bool AddHitToEvent(CompassHit& mhit);
vector<DPPChannel> GetEvent();
inline TH2F* GetEventStats() { return event_stats; };
void FlushHitsToEvent(); //For use with *last* hit list
inline bool IsEventReady() { return eventFlag; };
private:
void InitVariableMaps();
void Reset();
void StartEvent();
void ProcessEvent();
double coincWindow;
vector<DPPChannel> hitList;
vector<DPPChannel> event;
bool eventFlag;
DPPChannel hit;
double startTime, previousHitTime;
TH2F* event_stats;
};
#endif

30
include/Stopwatch.h Normal file
View File

@ -0,0 +1,30 @@
/*
Stopwatch.h
Simple class designed to provide timing info on parts of the process.
Only for use in development.
Written by G.W. McCann Oct. 2020
*/
#ifndef STOPWATCH_H
#define STOPWATCH_H
#include <chrono>
class Stopwatch {
public:
Stopwatch();
~Stopwatch();
void Start();
void Stop();
double GetElapsedSeconds();
double GetElapsedMilliseconds();
private:
using Time = std::chrono::high_resolution_clock::time_point;
using Clock = std::chrono::high_resolution_clock;
Time start_time, stop_time;
};
#endif

15
input.txt Normal file
View File

@ -0,0 +1,15 @@
-------Data Location----------
WorkspaceDirectory: /home/gwm17/working/GWM_EventBuilder/example
-------------------------------
------Experimental Inputs------
ScalerFile: /home/gwm17/working/GWM_EventBuilder/etc/ScalerFile.txt
-------------------------------
-------Timing Information------
BoardOffsetFile: /home/gwm17/working/GWM_EventBuilder/etc/ShiftMap_April2020_newFormat_10102020.txt
SlowCoincidenceWindow(ps): 1.5e+06
-------------------------------
--------Run Information--------
MinRun: 75
MaxRun: 75
BufferSize(hits): 200000
-------------------------------

7
lib/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
###ignore these files####
*.dylib
*.so
*.pcm
###keep this one###
!.gitignore

96
makefile Normal file
View File

@ -0,0 +1,96 @@
OS_NAME := $(shell uname -s)
CC=g++
ROOTCFLAGS= `root-config --cflags`
ROOTGLIBS=`root-config --glibs`
ROOTDICT_INCL=./
CFLAGS= -std=c++11 -fPIC -g -Wall $(ROOTCFLAGS)
INCLDIR=./include
SRCDIR=./src
BINDIR=./bin
LIBDIR=./lib
CPPFLAGS= -I$(INCLDIR)
LDFLAGS=$(ROOTGLIBS)
EVBSRCDIR=$(SRCDIR)/evb
GUISRCDIR=$(SRCDIR)/gui
OBJDIR=./objs
EVBSRC=$(wildcard $(EVBSRCDIR)/*.cpp)
GUISRC=$(wildcard $(GUISRCDIR)/*.cpp)
EVBOBJS=$(EVBSRC:$(EVBSRCDIR)/%.cpp=$(OBJDIR)/%.o)
GUIOBJS=$(GUISRC:$(GUISRCDIR)/%.cpp=$(OBJDIR)/%.o)
DICT_PAGES= $(INCLDIR)/DataStructs.h $(INCLDIR)/LinkDef_evb.h
DICT=$(SRCDIR)/evb_dict.cxx
DICTOBJ=$(OBJDIR)/evb_dict.o
DICTLIB=$(LIBDIR)/libEVBDict
GDICT_PAGES=$(INCLDIR)/EVBMainFrame.h $(INCLDIR)/FileViewFrame.h $(INCLDIR)/LinkDef_Gui.h
GDICT=$(SRCDIR)/gui_dict.cxx
GDICTOBJ=$(OBJDIR)/gui_dict.o
#entry points
EVBGUIMSRC=$(SRCDIR)/gui_main.cpp
EVBGUIMAIN=$(OBJDIR)/gui_main.o
EVBMSRC=$(SRCDIR)/main.cpp
EVBMAIN=$(OBJDIR)/main.o
PCH_FILE=$(INCLDIR)/EventBuilder.h
PCH=$(INCLDIR)/EventBuilder.h.gch
EVBEXE=$(BINDIR)/GWMEVB
EVBCLEXE=$(BINDIR)/GWMEVB_CL
EXES = $(EVBEXE) $(EVBCLEXE)
OBJS = $(EVBOBJS) $(GUIOBJS) $(DICTOBJ) $(GDICTOBJ) $(EVBGUIMAIN) $(EVBMAIN)
.PHONY: all clean clean_header
all: $(PCH) $(EVBEXE) $(EVBCLEXE)
$(PCH): $(PCH_FILE)
$(CC) $(CFLAGS) -x c++-header $^
$(EVBEXE): $(DICTOBJ) $(GDICTOBJ) $(EVBOBJS) $(GUIOBJS) $(EVBGUIMAIN)
$(CC) $^ -o $@ $(LDFLAGS)
$(EVBCLEXE): $(DICTOBJ) $(EVBOBJS) $(EVBMAIN)
$(CC) $^ -o $@ $(LDFLAGS)
$(DICTOBJ): $(DICT)
$(CC) $(CFLAGS) -I $(ROOTDICT_INCL) -o $@ -c $^
ifeq ($(OS_NAME), Darwin)
$(CC) $(CFLAGS) $(LDFLAGS) $@ -dynamiclib -o $(DICTLIB).dylib
cp $(SRCDIR)/*.pcm $(LIBDIR)
else
ifeq ($(OS_NAME), Linux)
$(CC) $(CFLAGS) $(LDFLAGS) $@ -shared -o $(DICTLIB).so
cp $(SRCDIR)/*.pcm $(LIBDIR)
endif
endif
mv $(SRCDIR)/*.pcm ./$(BINDIR)/
$(GDICTOBJ): $(GDICT)
$(CC) $(CFLAGS) -I $(ROOTDICT_INCL) -o $@ -c $^
mv $(SRCDIR)/*.pcm $(BINDIR)/
$(DICT): $(DICT_PAGES)
rootcint -f $@ $^
$(GDICT): $(GDICT_PAGES)
rootcint -f $@ $^
clean:
$(RM) $(OBJS) $(EXES) $(DICT) $(GDICT) $(DICTLIB) ./$(LIBDIR)/*.pcm ./$(BINDIR)/*.pcm
clean_header:
$(RM) $(PCH)
VPATH= $(SRCDIR):$(EVBSRCDIR):$(GUISRCDIR)
$(OBJDIR)/%.o: %.cpp
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $^

3
objs/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
### dont include any files, but include this dir ###
*
!.gitignore

3
src/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
###ignore the root dictionary generated file###
*.cxx
!.gitignore

164
src/evb/CompassFile.cpp Normal file
View File

@ -0,0 +1,164 @@
/*
CompassFile.cpp
Wrapper class around a shared pointer to an ifstream. Here the shared pointer is used
to overcome limitations of the ifstream class, namely that it is written such that ifstream
cannot be modified by move semantics. Contains all information needed to parse a single binary
CompassFile. Currently has a class wide defined buffer size; may want to make this user input
in the future.
Written by G.W. McCann Oct. 2020
*/
#include "EventBuilder.h"
#include "CompassFile.h"
CompassFile::CompassFile() :
m_filename(""), bufferIter(nullptr), bufferEnd(nullptr), m_smap(nullptr), hitUsedFlag(true), m_file(std::make_shared<std::ifstream>()), eofFlag(false)
{
m_buffersize = bufsize*hitsize;
hitBuffer.resize(m_buffersize);
}
CompassFile::CompassFile(const std::string& filename) :
m_filename(""), bufferIter(nullptr), bufferEnd(nullptr), m_smap(nullptr), hitUsedFlag(true), m_file(std::make_shared<std::ifstream>()), eofFlag(false)
{
m_buffersize = bufsize*hitsize;
hitBuffer.resize(m_buffersize);
Open(filename);
}
CompassFile::CompassFile(const std::string& filename, unsigned int bsize) :
m_filename(""), bufferIter(nullptr), bufferEnd(nullptr), m_smap(nullptr), hitUsedFlag(true),
bufsize(bsize), m_file(std::make_shared<std::ifstream>()), eofFlag(false)
{
m_buffersize = bufsize*hitsize;
hitBuffer.resize(m_buffersize);
Open(filename);
}
CompassFile::~CompassFile() {
Close();
}
void CompassFile::Open(const std::string& filename) {
eofFlag = false;
hitUsedFlag = true;
m_filename = filename;
m_file->open(m_filename, std::ios::binary | std::ios::in);
m_file->seekg(0, std::ios_base::end);
m_size = m_file->tellg();
if(m_size <= 24) {
eofFlag = true;
m_nHits = 0;
} else {
m_file->seekg(0, std::ios_base::beg);
hitsize = GetHitSize();
m_buffersize = hitsize*bufsize;
hitBuffer.resize(m_buffersize);
m_nHits = m_size/hitsize;
}
}
void CompassFile::Close() {
if(IsOpen()) {
m_file->close();
}
}
unsigned int CompassFile::GetHitSize() {
if(!IsOpen()) {
std::cerr<<"Unable to get hit size due to file not being open!"<<std::endl;
return 0;
}
char* firstHit = new char[24]; //A compass hit by default has 24 bytes (at least in our setup)
m_file->read(firstHit, 24);
uint32_t nsamples = *((uint32_t*) &firstHit[20]);
m_file->seekg(0, std::ios_base::beg);
delete[] firstHit;
return 24 + nsamples*4;
}
/*
GetNextHit() is the function which... gets the next hit
Has to check if the buffer needs refilled/filled for the first time
Upon pulling a hit, sets the UsedFlag to false, letting the next level know
that the hit should be free game.
If the file cannot be opened, signals as though file is EOF
*/
bool CompassFile::GetNextHit() {
if(!IsOpen()) return true;
if((bufferIter == nullptr || bufferIter == bufferEnd) && !IsEOF()) {
GetNextBuffer();
}
if(!IsEOF()) {
ParseNextHit();
hitUsedFlag = false;
}
return eofFlag;
}
/*
GetNextBuffer() ... self-explanatory name
Note tht this is where the EOF flag is set. The EOF is only singaled
after the LAST buffer is completely read (i.e literally no more data). ifstream sets its eof
bit upon pulling the last buffer, but this class waits until that entire
last buffer is read to singal EOF (the true end of file).
*/
void CompassFile::GetNextBuffer() {
if(m_file->eof()) {
eofFlag = true;
return;
}
m_file->read(hitBuffer.data(), hitBuffer.size());
bufferIter = hitBuffer.data();
bufferEnd = bufferIter + m_file->gcount(); //one past the last datum
}
void CompassFile::ParseNextHit() {
m_currentHit.board = *((UShort_t*)bufferIter);
bufferIter += 2;
m_currentHit.channel = *((UShort_t*)bufferIter);
bufferIter += 2;
m_currentHit.timestamp = *((ULong64_t*)bufferIter);
bufferIter += 8;
m_currentHit.lgate = *((UShort_t*)bufferIter);
bufferIter += 2;
m_currentHit.sgate = *((UShort_t*)bufferIter);
bufferIter += 2;
m_currentHit.flags = *((UInt_t*)bufferIter);
bufferIter += 4;
m_currentHit.Ns = *((UInt_t*)bufferIter);
bufferIter += 4;
if(m_smap != nullptr) { //memory safety
int gchan = m_currentHit.channel + m_currentHit.board*16;
m_currentHit.timestamp += m_smap->GetShift(gchan);
}
/*
if(m_currentHit.Ns*2 + 24 != hitsize) {
std::cerr<<"WARNING! Hit size does not match current value of samples... Try to proceed, but expect seg fault."<<std::endl;
return;
}
*/
for(unsigned int i=0; i<m_currentHit.Ns; i++) {
m_currentHit.samples.push_back(*((UShort_t*)bufferIter));
bufferIter += 2;
}
}

261
src/evb/CompassRun.cpp Normal file
View File

@ -0,0 +1,261 @@
/*
CompassRun.cpp
Class designed as abstraction of a collection of binary files that represent the total data in a single
Compass data run. It handles the user input (shift maps, file collection etc.) and creates a list of
CompassFiles from which to draw data. It then draws data from these files, organizes them in time,
and writes to a ROOT file for further processing.
Written by G.W. McCann Oct. 2020
Updated to also handle scaler data. -- GWM Oct. 2020
*/
#include "EventBuilder.h"
#include "CompassRun.h"
#include "RunCollector.h"
#include "SlowSort.h"
#include "FlagHandler.h"
CompassRun::CompassRun() :
directory(""), m_scalerinput(""), runNum(0), m_buffersize(200000), m_scaler_flag(false), m_pb(nullptr)
{
}
CompassRun::CompassRun(const std::string& dir, unsigned int bsize) :
directory(dir), m_scalerinput(""), runNum(0), m_buffersize(bsize), m_scaler_flag(false), m_pb(nullptr)
{
}
CompassRun::~CompassRun() {}
/*Load em into a map*/
void CompassRun::SetScalers() {
std::ifstream input(m_scalerinput);
if(!input.is_open()) return;
m_scaler_flag = true;
std::string junk, filename, varname;
Long64_t init = 0;
std::getline(input, junk);
std::getline(input, junk);
m_scaler_map.clear();
while(input>>filename) {
input>>varname;
filename = directory+filename+"_run_"+to_string(runNum)+".bin";
m_scaler_map[filename] = TParameter<Long64_t>(varname.c_str(), init);
}
input.close();
}
bool CompassRun::GetBinaryFiles() {
std::string prefix = "";
std::string suffix = ".bin"; //binaries
RunCollector grabber(directory, prefix, suffix);
grabber.GrabAllFiles();
m_datafiles.clear(); //so that the CompassRun can be reused
m_datafiles.reserve(grabber.filelist.size());
bool scalerd;
m_totalHits = 0; //reset total run size
for(auto& entry : grabber.filelist) {
//Handle scaler files, if they exist
if(m_scaler_flag) {
scalerd = false;
for(auto& scaler_pair : m_scaler_map) {
if(std::string(entry.Data()) == scaler_pair.first) {
ReadScalerData(entry.Data());
scalerd = true;
break;
}
}
if(scalerd) continue;
}
m_datafiles.emplace_back(entry.Data());
m_datafiles[m_datafiles.size()-1].AttachShiftMap(&m_smap);
//Any time we have a file that fails to be found, we terminate the whole process
if(!m_datafiles[m_datafiles.size() - 1].IsOpen()) {
return false;
}
m_totalHits += m_datafiles[m_datafiles.size()-1].GetNumberOfHits();
}
return true;
}
/*
Pure counting of scalers. Potential upgrade path to something like
average count rate etc.
*/
void CompassRun::ReadScalerData(const std::string& filename) {
if(!m_scaler_flag) return;
Long64_t count;
count = 0;
CompassFile file(filename);
auto& this_param = m_scaler_map[file.GetName()];
while(true) {
file.GetNextHit();
if(file.IsEOF()) break;
count++;
}
this_param.SetVal(count);
}
/*
GetHitsFromFiles() is the function which actually retrieves and sorts the data from the individual
files. There are several tricks which allow this to happen. First is that, after sorting, it is impossible
to determine which file the data originally came from (short of parsing the name of the file against board/channel).
However, we need to let the file know that we want it to pull the next hit. To do this, a pointer to the UsedFlag of the file
is retrieved along with the data. This flag is flipped so that on the next hit cycle a new hit is pulled. Second is the use
of a rolling start index. Once a file has gone EOF, we no longer need it. If this is the first file in the list, we can just skip
that index all together. In this way, the loop can go from N times to N-1 times.
*/
bool CompassRun::GetHitsFromFiles() {
std::pair<CompassHit, bool*> earliestHit = make_pair(CompassHit(), nullptr);
for(unsigned int i=startIndex; i<m_datafiles.size(); i++) {
if(m_datafiles[i].CheckHitHasBeenUsed()) {
m_datafiles[i].GetNextHit();
}
if(m_datafiles[i].IsEOF()) {
if(i == startIndex) startIndex++;
continue;
} else if(i == startIndex) {
earliestHit = make_pair(m_datafiles[i].GetCurrentHit(), m_datafiles[i].GetUsedFlagPtr());
} else if(m_datafiles[i].GetCurrentHit().timestamp < earliestHit.first.timestamp) {
earliestHit = make_pair(m_datafiles[i].GetCurrentHit(), m_datafiles[i].GetUsedFlagPtr());
}
}
if(earliestHit.second == nullptr) return false; //Make sure that there actually was a hit
hit = earliestHit.first;
*earliestHit.second = true;
return true;
}
void CompassRun::Convert2RawRoot(const std::string& name) {
TFile* output = TFile::Open(name.c_str(), "RECREATE");
TTree* outtree = new TTree("Data", "Data");
outtree->Branch("Board", &hit.board);
outtree->Branch("Channel", &hit.channel);
outtree->Branch("Energy", &hit.lgate);
outtree->Branch("EnergyShort", &hit.sgate);
outtree->Branch("Timestamp", &hit.timestamp);
outtree->Branch("Flags", &hit.flags);
if(!m_smap.IsSet()) {
std::cerr<<"Bad shift map at CompassRun::Convert()."<<std::endl;
std::cerr<<"Shifts will be locked to 0"<<std::endl;
}
SetScalers();
if(!GetBinaryFiles()) {
std::cerr<<"Unable to open a file!"<<std::endl;
return;
}
if(m_pb) SetProgressBar();
startIndex = 0; //Reset the startIndex
unsigned int count = 0, flush = m_totalHits*0.01, flush_count = 0;
if(flush == 0) flush = 1;
while(true) {
count++;
if(count == flush) { //Progress Log
if(m_pb) {
m_pb->Increment(count);
gSystem->ProcessEvents();
count=0;
} else {
count = 0;
flush_count++;
std::cout<<"\rPercent of run built: "<<flush_count*10<<"%"<<std::flush;
}
}
if(!GetHitsFromFiles()) break;
outtree->Fill();
}
output->cd();
outtree->Write(outtree->GetName(), TObject::kOverwrite);
for(auto& entry : m_scaler_map) {
entry.second.Write();
}
output->Close();
}
void CompassRun::Convert2SortedRoot(const std::string& name, double window) {
TFile* output = TFile::Open(name.c_str(), "RECREATE");
TTree* outtree = new TTree("SortTree", "SortTree");
outtree->Branch("event", &event);
if(!m_smap.IsSet()) {
std::cerr<<"Bad shift map at CompassRun::Convert()."<<std::endl;
std::cerr<<"Shifts will be locked to 0"<<std::endl;
}
SetScalers();
if(!GetBinaryFiles()) {
std::cerr<<"Unable to open a file!"<<std::endl;
return;
}
if(m_pb) SetProgressBar();
startIndex = 0;
SlowSort coincidizer(window);
bool killFlag = false;
unsigned int count = 0, flush = m_totalHits*0.01, flush_count = 0;
if(flush == 0) flush = 1;
while(true) {
count++;
if(count == flush) {
if(m_pb) {
m_pb->Increment(count);
gSystem->ProcessEvents();
count=0;
} else {
count = 0;
flush_count++;
std::cout<<"\rPercent of run built: "<<flush_count*10<<"%"<<std::flush;
}
}
if(!GetHitsFromFiles()) {
coincidizer.FlushHitsToEvent();
killFlag = true;
} else {
coincidizer.AddHitToEvent(hit);
}
if(coincidizer.IsEventReady()) {
event = coincidizer.GetEvent();
outtree->Fill();
if(killFlag) break;
}
}
output->cd();
outtree->Write(outtree->GetName(), TObject::kOverwrite);
for(auto& entry : m_scaler_map) {
entry.second.Write();
}
coincidizer.GetEventStats()->Write();
output->Close();
}
void CompassRun::SetProgressBar() {
m_pb->SetMax(m_totalHits);
m_pb->SetMin(0);
m_pb->SetPosition(0);
gSystem->ProcessEvents();
}

86
src/evb/FlagHandler.cpp Normal file
View File

@ -0,0 +1,86 @@
#include "EventBuilder.h"
#include "FlagHandler.h"
FlagHandler::FlagHandler() :
log("./event_log.txt")
{
}
FlagHandler::FlagHandler(const std::string& filename) :
log(filename)
{
}
FlagHandler::~FlagHandler() {
WriteLog();
log.close();
}
void FlagHandler::CheckFlag(int board, int channel, int flag) {
int gchan = channel + board*16;
FlagCount& counter = event_count_map[gchan]; //yikes
counter.total_counts++;
if(flag & DEAD_TIME) counter.dead_time++;
if(flag & TIME_ROLLOVER) counter.time_roll++;
if(flag & TIME_RESET) counter.time_reset++;
if(flag & FAKE_EVENT) counter.fake_event++;
if(flag & MEM_FULL) counter.mem_full++;
if(flag & TRIG_LOST) counter.trig_lost++;
if(flag & N_TRIG_LOST) counter.n_trig_lost++;
if(flag & SATURATING_IN_GATE) counter.sat_in_gate++;
if(flag & TRIG_1024_COUNTED) counter.trig_1024++;;
if(flag & SATURATING_INPUT) counter.sat_input++;
if(flag & N_TRIG_COUNTED) counter.n_trig_count++;
if(flag & EVENT_NOT_MATCHED) counter.event_not_matched++;
if(flag & PILE_UP) counter.pile_up++;
if(flag & PLL_LOCK_LOSS) counter.pll_lock_loss++;
if(flag & OVER_TEMP) counter.over_temp++;
if(flag & ADC_SHUTDOWN) counter.adc_shutdown++;
}
void FlagHandler::WriteLog() {
log<<"Event Flag Log"<<std::endl;
log<<"-----------------------------"<<std::endl;
for(auto& counter : event_count_map) {
log<<"-----------------------------"<<std::endl;
log<<"GLOBAL CHANNEL No.: "<<counter.first<<std::endl;
log<<"Total number of events: "<<counter.second.total_counts<<std::endl;
log<<"Dead time incurred (only for V1724): "<<counter.second.dead_time<<std::endl;
log<<"Timestamp rollovers: "<<counter.second.time_roll<<std::endl;
log<<"Timestamp resets from external: "<<counter.second.time_reset<<std::endl;
log<<"Fake events: "<<counter.second.fake_event<<std::endl;
log<<"Memory full: "<<counter.second.mem_full<<std::endl;
log<<"Triggers lost: "<<counter.second.trig_lost<<std::endl;
log<<"N Triggers lost: "<<counter.second.n_trig_lost<<std::endl;
log<<"Saturation within the gate: "<<counter.second.sat_in_gate<<std::endl;
log<<"1024 Triggers found: "<<counter.second.trig_1024<<std::endl;
log<<"Saturation on input: "<<counter.second.sat_input<<std::endl;
log<<"N Triggers counted: "<<counter.second.n_trig_count<<std::endl;
log<<"Events not matched: "<<counter.second.event_not_matched<<std::endl;
log<<"Pile ups: "<<counter.second.pile_up<<std::endl;
log<<"PLL lock lost: "<<counter.second.pll_lock_loss<<std::endl;
log<<"Over Temperature: "<<counter.second.over_temp<<std::endl;
log<<"ADC Shutdown: "<<counter.second.adc_shutdown<<std::endl;
log<<"-----------------------------"<<std::endl;
}
}

200
src/evb/GWMEventBuilder.cpp Normal file
View File

@ -0,0 +1,200 @@
/*
GWMEventBuilder.cpp
Class which represents the API of the event building environment. Wraps together the core concepts
of the event builder, from conversion to plotting. Even intended to be able to archive data.
Currently under development.
Written by G.W. McCann Oct. 2020
*/
#include "EventBuilder.h"
#include <cstdlib>
#include "GWMEventBuilder.h"
#include "RunCollector.h"
#include "CompassRun.h"
GWMEventBuilder::GWMEventBuilder() :
m_rmin(0), m_rmax(0), m_workspace("none"), m_shiftfile("none"), m_SlowWindow(0), m_buffersize(200000), m_pb(nullptr)
{
}
GWMEventBuilder::~GWMEventBuilder()
{
}
bool GWMEventBuilder::ReadConfigFile(const std::string& fullpath) {
std::cout<<"Reading in configuration from file: "<<fullpath<<std::endl;
std::ifstream input(fullpath);
if(!input.is_open()) {
std::cout<<"Read failed! Unable to open input file!"<<std::endl;
return false;
}
std::string junk;
std::getline(input, junk);
input>>junk>>m_workspace;
input>>junk;
std::getline(input, junk);
std::getline(input, junk);
input>>junk>>m_scalerfile;
input>>junk;
std::getline(input, junk);
std::getline(input, junk);
input>>junk>>m_shiftfile;
input>>junk>>m_SlowWindow;
input>>junk;
std::getline(input, junk);
std::getline(input, junk);
input>>junk>>m_rmin;
input>>junk>>m_rmax;
input>>junk>>m_buffersize;
input.close();
std::cout<<"Completed."<<std::endl;
return true;
}
void GWMEventBuilder::WriteConfigFile(const std::string& fullpath) {
std::cout<<"Writing out configuration to file: "<<fullpath<<std::endl;
std::ofstream output(fullpath);
if(!output.is_open()) {
std::cout<<"Write failed! Unable to open output file!"<<std::endl;
return;
}
output<<"-------Data Location----------"<<std::endl;
output<<"WorkspaceDirectory: "<<m_workspace<<std::endl;
output<<"-------------------------------"<<std::endl;
output<<"------Experimental Inputs------"<<std::endl;
output<<"ScalerFile: "<<m_scalerfile<<std::endl;
output<<"-------------------------------"<<std::endl;
output<<"-------Timing Information------"<<std::endl;
output<<"BoardOffsetFile: "<<m_shiftfile<<std::endl;
output<<"SlowCoincidenceWindow(ps): "<<m_SlowWindow<<std::endl;
output<<"-------------------------------"<<std::endl;
output<<"--------Run Information--------"<<std::endl;
output<<"MinRun: "<<m_rmin<<std::endl;
output<<"MaxRun: "<<m_rmax<<std::endl;
output<<"BufferSize: "<<m_buffersize<<std::endl;
output<<"-------------------------------"<<std::endl;
output.close();
std::cout<<"Completed."<<std::endl;
}
void GWMEventBuilder::Convert2RawRoot() {
std::string rawroot_dir = m_workspace+"/raw_root/";
std::string unpack_dir = m_workspace+"/temp_binary/";
std::string binary_dir = m_workspace+"/raw_binary/";
std::cout<<"-------------GWM Event Builder-------------"<<std::endl;
std::cout<<"Converting Binary file Archive to ROOT file"<<std::endl;
std::cout<<"Binary Archive Directory: "<<binary_dir<<std::endl;
std::cout<<"Temporary Unpack Directory: "<<unpack_dir<<std::endl;
std::cout<<"Timestamp Shift File: "<<m_shiftfile<<std::endl;
std::cout<<"Min Run: "<<m_rmin<<" Max Run: "<<m_rmax<<std::endl;
std::cout<<"Buffer Size in hits: "<<m_buffersize<<std::endl;
grabber.SetSearchParams(binary_dir, "", ".tar.gz",0,1000);
std::cout<<"Workspace Directory: "<<m_workspace<<std::endl;
std::string rawfile, binfile;
std::string unpack_command, wipe_command;
CompassRun converter(unpack_dir, m_buffersize);
converter.SetShiftMap(m_shiftfile);
converter.SetScalerInput(m_scalerfile);
if(m_pb) converter.AttachProgressBar(m_pb);
std::cout<<"Beginning conversion..."<<std::endl;
for(int i=m_rmin; i<=m_rmax; i++) {
binfile = grabber.GrabFile(i);
if(binfile == "") continue;
converter.SetRunNumber(i);
std::cout<<"Converting file: "<<binfile<<std::endl;
rawfile = rawroot_dir + "compass_run_"+ to_string(i) + ".root";
unpack_command = "tar -xzf "+binfile+" --directory "+unpack_dir;
wipe_command = "rm -r "+unpack_dir+"*.bin";
system(unpack_command.c_str());
converter.Convert2RawRoot(rawfile);
system(wipe_command.c_str());
}
std::cout<<std::endl<<"Conversion complete."<<std::endl;
std::cout<<"-------------------------------------------"<<std::endl;
}
void GWMEventBuilder::MergeROOTFiles() {
std::string merge_file = m_workspace+"/merged/run_"+to_string(m_rmin)+"_"+to_string(m_rmax)+".root";
std::string file_dir = m_workspace+"/analyzed/";
std::cout<<"-------------GWM Event Builder-------------"<<std::endl;
std::cout<<"Merging ROOT files into single ROOT file"<<std::endl;
std::cout<<"Workspace directory: "<<m_workspace<<std::endl;
std::cout<<"Min Run: "<<m_rmin<<" Max Run: "<<m_rmax<<std::endl;
std::cout<<"Output file: "<<merge_file<<std::endl;
std::string prefix = "";
std::string suffix = ".root";
grabber.SetSearchParams(file_dir, prefix, suffix,m_rmin,m_rmax);
std::cout<<"Beginning the merge...";
if(!grabber.Merge_TChain(merge_file)) {
std::cout<<"Unable to find files at MergeROOTFiles"<<std::endl;
return;
}
std::cout<<" Complete."<<std::endl;
std::cout<<"-------------------------------------------"<<std::endl;
}
void GWMEventBuilder::Convert2SortedRoot() {
std::string sortroot_dir = m_workspace+"/sorted/";
std::string unpack_dir = m_workspace+"/temp_binary/";
std::string binary_dir = m_workspace+"/raw_binary/";
std::cout<<"-------------GWM Event Builder-------------"<<std::endl;
std::cout<<"Converting Binary file Archive to ROOT file"<<std::endl;
std::cout<<"Binary Archive Directory: "<<binary_dir<<std::endl;
std::cout<<"Temporary Unpack Directory: "<<unpack_dir<<std::endl;
std::cout<<"Timestamp Shift File: "<<m_shiftfile<<std::endl;
std::cout<<"Slow Coincidence Window(ps): "<<m_SlowWindow<<std::endl;
std::cout<<"Min Run: "<<m_rmin<<" Max Run: "<<m_rmax<<std::endl;
std::cout<<"Buffer Size in hits: "<<m_buffersize<<std::endl;
grabber.SetSearchParams(binary_dir,"",".tar.gz",m_rmin,m_rmax);
std::cout<<"Workspace Directory: "<<m_workspace<<std::endl;
std::string sortfile, binfile;
std::string unpack_command, wipe_command;
CompassRun converter(unpack_dir, m_buffersize);
converter.SetShiftMap(m_shiftfile);
converter.SetScalerInput(m_scalerfile);
if(m_pb) converter.AttachProgressBar(m_pb);
std::cout<<"Beginning conversion..."<<std::endl;
for(int i=m_rmin; i<= m_rmax; i++) {
binfile = grabber.GrabFile(i);
if(binfile == "") continue;
converter.SetRunNumber(i);
std::cout<<"Converting file: "<<binfile<<std::endl;
sortfile = sortroot_dir +"run_"+to_string(i)+ ".root";
unpack_command = "tar -xzf "+binfile+" --directory "+unpack_dir;
wipe_command = "rm -r "+unpack_dir+"*.bin";
system(unpack_command.c_str());
converter.Convert2SortedRoot(sortfile, m_SlowWindow);
system(wipe_command.c_str());
}
std::cout<<std::endl<<"Conversion complete."<<std::endl;
std::cout<<"-------------------------------------------"<<std::endl;
}

37
src/evb/OrderChecker.cpp Normal file
View File

@ -0,0 +1,37 @@
/*
OrderChecker.cpp
Very simple class designed to test whether or not a root file is time ordered.
Meant to be used with newly converted from binary data. Only for development.
Written by G.W. McCann Oct. 2020
*/
#include "EventBuilder.h"
#include "OrderChecker.h"
OrderChecker::OrderChecker() {
}
OrderChecker::~OrderChecker() {
}
bool OrderChecker::IsOrdered(const std::string& filename) {
TFile* file = TFile::Open(filename.c_str(), "READ");
TTree* tree = (TTree*) file->Get("Data");
ULong64_t ts;
tree->SetBranchAddress("Timestamp", &ts);
ULong64_t prevStamp = 0;
for(Long64_t i=0; i<tree->GetEntries(); i++) {
tree->GetEntry();
if(prevStamp >= ts) {
std::cerr<<"Bad order at entry "<<i<<" out of "<<tree->GetEntries()<<std::endl;
return false;
}
}
file->Close();
return true;
}

196
src/evb/RunCollector.cpp Normal file
View File

@ -0,0 +1,196 @@
#include "EventBuilder.h"
#include "RunCollector.h"
using namespace std;
RunCollector::RunCollector():
initFlag(false), dir(""), run(""), end(""), MaxRun(0), MinRun(0)
{
}
RunCollector::RunCollector(const string& dirname, const string& prefix, const string& suffix) {
dir = dirname.c_str();
run = prefix.c_str();
end = suffix.c_str();
MinRun = 0; MaxRun = LITERALMAX;
initFlag = true;
}
RunCollector::RunCollector(const string& dirname, const string& prefix, const string& suffix, int min, int max) {
dir = dirname.c_str();
run = prefix.c_str();
end = suffix.c_str();
MinRun = min; MaxRun = max;
initFlag = true;
}
RunCollector::~RunCollector() {}
void RunCollector::SetSearchParams(const string& dirname, const string& prefix, const string& suffix, int min, int max) {
dir = dirname.c_str();
run = prefix.c_str();
end = suffix.c_str();
MinRun = min; MaxRun = max;
initFlag = true;
}
int RunCollector::GrabAllFiles() {
if(!initFlag) {return 0;}
TSystemDirectory sysdir(dir.Data(), dir.Data());
TList *flist = sysdir.GetListOfFiles();
filelist.clear();
int counter = 0;
if(flist) { //Make sure list is real. If not, means no directory
TSystemFile *file;
TString fname, temp;
TIter next_element(flist); //List iterator
while((file = (TSystemFile*)next_element())) {
temp = file->GetName();
if(!file->IsDirectory() && temp.BeginsWith(run.Data()) && temp.EndsWith(end.Data())) {
counter++;
fname = dir+temp;
filelist.push_back(fname);
}
}
if(counter>0) {
delete flist;
return 1;
} else {
cerr<<"Unable to find files with matching run name in directory; check input.txt"<<endl;
delete flist;
return 0;
}
} else {
cerr<<"Unable to find any files in directory; check name given to the input.txt"<<endl;
delete flist;
return 0;
}
}
std::string RunCollector::GrabFile(int runNum) {
if(!initFlag) return "";
TSystemDirectory sysdir(dir.Data(), dir.Data());
TList* flist = sysdir.GetListOfFiles();
if(!flist) return "";
TSystemFile *file;
TString fname = "", temp;
string runno = "_"+to_string(runNum)+end.Data();
TIter next_element(flist);
while((file = (TSystemFile*)next_element())) {
temp = file->GetName();
if(!file->IsDirectory() && temp.BeginsWith(run.Data()) && temp.EndsWith(runno.c_str())) {
fname = dir+temp;
break;
}
}
return fname.Data();
}
/*Grabs all files within a specified run range*/
int RunCollector::GrabFilesInRange() {
if(!initFlag) {return 0;}
TSystemDirectory sysdir(dir.Data(), dir.Data());
TList *flist = sysdir.GetListOfFiles();
filelist.clear();
int counter = 0;
if(flist) {
TSystemFile *file;
TString fname, temp;
string runno;
for(int i=MinRun; i<=MaxRun; i++) {//loop over range
TIter next_element(flist);//list iterator
runno = "_"+to_string(i) + end.Data(); //suffix is now _#.endData
while((file = (TSystemFile*)next_element())) {//look through directory until file found
temp = file->GetName();
if(!file->IsDirectory()&&temp.BeginsWith(run.Data())&&temp.EndsWith(runno.c_str())){
counter++;
fname = dir+temp;
filelist.push_back(fname);
break; //if we find the file, break out of iterator loop
}
}
}
if(counter>0) {
delete flist;
return 1;
} else {
cerr<<"Unable to find files with matching run name in directory; check input.txt"<<endl;
delete flist;
return 0;
}
} else {
cerr<<"Unable to find any files in directory; check name given to input.txt"<<endl;
delete flist;
return 0;
}
}
int RunCollector::Merge_hadd(const string& outname) {
if(!initFlag) {return 0;}
if(MaxRun == LITERALMAX) {
if(GrabAllFiles()) {
TString clump = "hadd "+outname;
for(unsigned int i=0; i<filelist.size(); i++) {
clump += " "+filelist[i];
}
cout<<"Merging runs into single file..."<<endl;
system(clump.Data());
cout<<"Finished merging"<<endl;
return 1;
} else {
return 0;
}
} else {
if(GrabFilesInRange()) {
TString clump = "hadd "+outname;
for(unsigned int i=0; i<filelist.size(); i++) {
clump += " "+filelist[i];
}
cout<<"Merging runs "<<MinRun<<" to "<<MaxRun<<" into a single file..."<<endl;
system(clump.Data());
cout<<"Finished merging"<<endl;
return 1;
} else {
return 0;
}
}
}
int RunCollector::Merge_TChain(const string& outname) {
if(!initFlag) {return 0;}
TFile *output = new TFile(outname.c_str(), "RECREATE");
TChain *chain = new TChain("SPSTree", "SPSTree");
if(MaxRun == LITERALMAX) {
if(GrabAllFiles()) {
for(unsigned int i=0; i<filelist.size(); i++) {
chain->Add(filelist[i].Data());
}
cout<<"Merging runs into single file..."<<endl;
chain->Merge(output,0,"fast");
cout<<"Finished merging"<<endl;
return 1;
} else {
return 0;
}
} else {
if(GrabFilesInRange()) {
for(unsigned int i=0; i<filelist.size(); i++) {
chain->Add(filelist[i]);
}
cout<<"Merging runs "<<MinRun<<" to "<<MaxRun<<" into a single file..."<<endl;
chain->Merge(output,0,"fast");
cout<<"Finished merging"<<endl;
return 1;
} else {
return 0;
}
}
if(output->IsOpen()) output->Close();
return 0;
}

69
src/evb/ShiftMap.cpp Normal file
View File

@ -0,0 +1,69 @@
/*
ShiftMap.h
New class to act a go-between for timestamp shifts to channels. Takes in a
formated file containing data for shifts and then stores them in an unordered_map.
Key is a global compass channel (board#*16 + channel). Shifts in ps.
Note: Timestamps are now shifted in binary conversion. This means that shifts *MUST*
be stored as Long64_t types. No decimals!
Written by G.W. McCann Oct. 2020
*/
#include "EventBuilder.h"
#include "ShiftMap.h"
ShiftMap::ShiftMap() :
m_filename(""), is_set(false)
{
}
ShiftMap::ShiftMap(const std::string& filename) :
m_filename(filename), is_set(false)
{
ParseFile();
}
ShiftMap::~ShiftMap() {}
void ShiftMap::SetFile(const std::string& filename) {
m_filename = filename;
ParseFile();
}
Long64_t ShiftMap::GetShift(int gchan) {
if(!is_set) return 0.0;
auto iter = m_map.find(gchan);
if(iter == m_map.end()) {
return 0.0;
} else return iter->second;
}
void ShiftMap::ParseFile() {
std::ifstream input(m_filename);
if(!input.is_open()) return;
int board, channel, gchan;
Long64_t shift;
std::string junk, temp;
std::getline(input, junk);
std::getline(input, junk);
while(input>>board) {
input>>temp;
input>>shift;
if(temp == "all") { //keyword to set all channels in this board to same shift
for(int i=0; i<16; i++) {
gchan = board*16 + i;
m_map[gchan] = shift;
}
} else {
channel = stoi(temp);
gchan = channel + board*16;
m_map[gchan] = shift;
}
}
is_set = true;
}

87
src/evb/SlowSort.cpp Normal file
View File

@ -0,0 +1,87 @@
/*SlowSort.cpp
*Class designed to first time-order raw data, and then based on a given coincidence window
*sort the raw data into coincidence structures. Utilizes dictionary elements DPPChannel and
*CoincEvent. Based on work by S. Balak, K. Macon, and E. Good from LSU.
*
*Gordon M. Oct. 2019
*
*Refurbished and updated Jan 2020 GWM
*/
#include "EventBuilder.h"
#include "SlowSort.h"
/*Constructor takes input of coincidence window size, and fills sabre channel map*/
SlowSort::SlowSort() :
coincWindow(-1.0), eventFlag(false)
{
event_stats = new TH2F("coinc_event_stats","coinc_events_stats;global channel;number of coincident hits;counts",144,0,144,20,0,20);
}
SlowSort::SlowSort(double windowSize) :
coincWindow(windowSize), eventFlag(false)
{
event_stats = new TH2F("coinc_event_stats","coinc_events_stats;global channel;number of coincident hits;counts",144,0,144,20,0,20);
}
SlowSort::~SlowSort() {
}
bool SlowSort::AddHitToEvent(CompassHit& mhit) {
DPPChannel curHit;
curHit.Timestamp = mhit.timestamp/1.0e3; //convert to ns for easier drawing
curHit.Energy = mhit.lgate;
curHit.EnergyShort = mhit.sgate;
curHit.Channel = mhit.channel;
curHit.Board = mhit.board;
curHit.Flags = mhit.flags;
curHit.Samples = mhit.samples;
if(hitList.empty()) {
startTime = curHit.Timestamp;
hitList.push_back(curHit);
} else if (curHit.Timestamp < previousHitTime) {
return false;
} else if ((curHit.Timestamp - startTime) < coincWindow) {
hitList.push_back(curHit);
} else {
ProcessEvent();
hitList.clear();
startTime = curHit.Timestamp;
hitList.push_back(curHit);
eventFlag = true;
}
return true;
}
void SlowSort::FlushHitsToEvent() {
if(hitList.empty()) {
eventFlag = false;
return;
}
ProcessEvent();
hitList.clear();
eventFlag = true;
}
vector<DPPChannel> SlowSort::GetEvent() {
eventFlag = false;
return event;
}
/*Function called when a start of a coincidence event is detected*/
void SlowSort::StartEvent() {
if(hitList.size() != 0) {
cerr<<"Attempting to initalize hitList when not cleared!! Check processing order."<<endl;
}
startTime = hit.Timestamp;
hitList.push_back(hit);
}
/*Function called when an event outside the coincidence window is detected
*Process all of the hits in the list, and write them to the sorted tree
*/
void SlowSort::ProcessEvent() {
event = hitList;
}

32
src/evb/Stopwatch.cpp Normal file
View File

@ -0,0 +1,32 @@
/*
Stopwatch.cpp
Simple class designed to provide timing info on parts of the process.
Only for use in development.
Written by G.W. McCann Oct. 2020
*/
#include "EventBuilder.h"
#include "Stopwatch.h"
Stopwatch::Stopwatch() {
start_time = Clock::now();
stop_time = start_time;
}
Stopwatch::~Stopwatch() {}
void Stopwatch::Start() {
start_time = Clock::now();
}
void Stopwatch::Stop() {
stop_time = Clock::now();
}
double Stopwatch::GetElapsedSeconds() {
return std::chrono::duration_cast<std::chrono::duration<double>>(stop_time-start_time).count();
}
double Stopwatch::GetElapsedMilliseconds() {
return std::chrono::duration_cast<std::chrono::duration<double>>(stop_time-start_time).count()*1000.0;
}

293
src/gui/EVBMainFrame.cpp Normal file
View File

@ -0,0 +1,293 @@
#include "EventBuilder.h"
#include "EVBMainFrame.h"
#include "FileViewFrame.h"
#include <TGLabel.h>
#include <TGTextBuffer.h>
#include <TApplication.h>
#include <TSystem.h>
EVBMainFrame::EVBMainFrame(const TGWindow* p, UInt_t w, UInt_t h) :
TGMainFrame(p, w, h, kVerticalFrame)
{
SetCleanup(kDeepCleanup);
MAIN_W = w; MAIN_H = h;
//Organization hints
TGLayoutHints *fchints = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY,5,5,5,5);
TGLayoutHints *fhints = new TGLayoutHints(kLHintsExpandX|kLHintsCenterY,5,5,5,5);
TGLayoutHints *lhints = new TGLayoutHints(kLHintsCenterY|kLHintsLeft,5,5,5,5);
TGLayoutHints *bhints = new TGLayoutHints(kLHintsLeft|kLHintsCenterY,5,5,5,5);
TGLayoutHints *fpbhints = new TGLayoutHints(kLHintsExpandX|kLHintsBottom,5,5,5,5);
TGLayoutHints *mhints = new TGLayoutHints(kLHintsTop|kLHintsLeft,0,4,0,0);
//Make the containers and link up all signals/slots
TGVerticalFrame *InputFrame = new TGVerticalFrame(this, w, h*0.9);
TGVerticalFrame *NameFrame = new TGVerticalFrame(InputFrame, w, h*0.4);
TGHorizontalFrame *WorkFrame = new TGHorizontalFrame(NameFrame, w, h*0.1);
TGLabel* workLabel = new TGLabel(WorkFrame, "Workspace Directory:");
fWorkField = new TGTextEntry(WorkFrame, new TGTextBuffer(120), WORKDIR);
fWorkField->Resize(w*0.25, fWorkField->GetDefaultHeight());
fWorkField->Connect("ReturnPressed()","EVBMainFrame",this,"UpdateWorkdir()");
fOpenWorkButton = new TGTextButton(WorkFrame, "Open");
fOpenWorkButton->Connect("Clicked()","EVBMainFrame",this,"DoOpenWorkdir()");
WorkFrame->AddFrame(workLabel, lhints);
WorkFrame->AddFrame(fWorkField, fhints);
WorkFrame->AddFrame(fOpenWorkButton, bhints);
TGHorizontalFrame *SMapFrame = new TGHorizontalFrame(NameFrame, w, h*0.1);
TGLabel* smaplabel = new TGLabel(SMapFrame, "Board Shift File:");
fSMapField = new TGTextEntry(SMapFrame, new TGTextBuffer(120), SMAP);
fSMapField->Resize(w*0.25, fSMapField->GetDefaultHeight());
fSMapField->Connect("ReturnPressed()","EVBMainFrame",this,"UpdateSMap()");
fOpenSMapButton = new TGTextButton(SMapFrame, "Open");
fOpenSMapButton->Connect("Clicked()","EVBMainFrame",this,"DoOpenSMapfile()");
SMapFrame->AddFrame(smaplabel, lhints);
SMapFrame->AddFrame(fSMapField, fhints);
SMapFrame->AddFrame(fOpenSMapButton, bhints);
TGHorizontalFrame *ScalerFrame = new TGHorizontalFrame(NameFrame, w, h*0.1);
TGLabel* sclabel = new TGLabel(ScalerFrame, "Scaler File: ");
fScalerField = new TGTextEntry(ScalerFrame, new TGTextBuffer(120), SCALER);
fScalerField->Connect("ReturnPressed()","EVBMainFrame",this,"UpdateScaler()");
fOpenScalerButton = new TGTextButton(ScalerFrame, "Open");
fOpenScalerButton->Connect("Clicked()","EVBMainFrame", this, "DoOpenScalerfile()");
ScalerFrame->AddFrame(sclabel, lhints);
ScalerFrame->AddFrame(fScalerField, fhints);
ScalerFrame->AddFrame(fOpenScalerButton, bhints);
NameFrame->AddFrame(WorkFrame, fhints);
NameFrame->AddFrame(SMapFrame, fhints);
NameFrame->AddFrame(ScalerFrame, fhints);
TGHorizontalFrame *WindowFrame = new TGHorizontalFrame(InputFrame, w, h*0.1);
TGLabel *slowlabel = new TGLabel(WindowFrame, "Slow Coincidence Window (ps):");
fSlowWindowField = new TGNumberEntryField(WindowFrame, SLOWWIND, 0, TGNumberEntry::kNESReal, TGNumberEntry::kNEANonNegative);
TGLabel *buflabel = new TGLabel(WindowFrame, "Buffer Size (hits):");
fBufferSizeField = new TGNumberEntryField(WindowFrame, BUFSIZE, 200000, TGNumberEntry::kNESInteger, TGNumberEntry::kNEANonNegative);
WindowFrame->AddFrame(slowlabel, lhints);
WindowFrame->AddFrame(fSlowWindowField, fhints);
WindowFrame->AddFrame(buflabel, lhints);
WindowFrame->AddFrame(fBufferSizeField, fhints);
TGHorizontalFrame *RunFrame = new TGHorizontalFrame(InputFrame, w, h*0.1);
TGLabel *typelabel = new TGLabel(RunFrame, "Operation Type:");
fTypeBox = new TGComboBox(RunFrame, TYPEBOX);
//Needs modification for new conversion based sorting GWM -- Dec 2020
fTypeBox->AddEntry("Convert Slow", GWMEventBuilder::CONVERT_S);
fTypeBox->AddEntry("Convert", GWMEventBuilder::CONVERT);
fTypeBox->AddEntry("Merge ROOT", GWMEventBuilder::MERGE);
fTypeBox->Resize(200,20);
fTypeBox->Connect("Selected(Int_t, Int_t)","EVBMainFrame",this,"HandleTypeSelection(Int_t,Int_t)");
TGLabel *rminlabel = new TGLabel(RunFrame, "Min Run:");
fRMinField = new TGNumberEntryField(RunFrame, RMIN, 0, TGNumberEntry::kNESInteger, TGNumberEntry::kNEANonNegative);
TGLabel *rmaxlabel = new TGLabel(RunFrame, "Max Run:");
fRMaxField = new TGNumberEntryField(RunFrame, RMAX, 0, TGNumberEntry::kNESInteger, TGNumberEntry::kNEANonNegative);
fRunButton = new TGTextButton(RunFrame, "Run!");
fRunButton->SetState(kButtonDisabled);
fRunButton->Connect("Clicked()","EVBMainFrame",this,"DoRun()");
RunFrame->AddFrame(typelabel, lhints);
RunFrame->AddFrame(fTypeBox, fhints);
RunFrame->AddFrame(rminlabel, lhints);
RunFrame->AddFrame(fRMinField, fhints);
RunFrame->AddFrame(rmaxlabel, lhints);
RunFrame->AddFrame(fRMaxField, fhints);
RunFrame->AddFrame(fRunButton, bhints);
InputFrame->AddFrame(NameFrame, fhints);
InputFrame->AddFrame(WindowFrame, fhints);
InputFrame->AddFrame(RunFrame, fhints);
TGVerticalFrame *PBFrame = new TGVerticalFrame(this, w, h*0.1);
TGLabel *pbLabel = new TGLabel(PBFrame, "Build Progress");
fProgressBar = new TGHProgressBar(PBFrame, TGProgressBar::kFancy, w);
fProgressBar->ShowPosition();
fProgressBar->SetBarColor("lightblue");
fBuilder.AttachProgressBar(fProgressBar);
PBFrame->AddFrame(pbLabel, lhints);
PBFrame->AddFrame(fProgressBar, fhints);
TGMenuBar* menuBar = new TGMenuBar(this, w, h*0.1);
fFileMenu = new TGPopupMenu(gClient->GetRoot());
fFileMenu->AddEntry("Load...", M_LOAD_CONFIG);
fFileMenu->AddEntry("Save...", M_SAVE_CONFIG);
fFileMenu->AddEntry("Exit", M_EXIT);
fFileMenu->Connect("Activated(Int_t)","EVBMainFrame", this, "HandleMenuSelection(Int_t)");
menuBar->AddPopup("File", fFileMenu, mhints);
AddFrame(menuBar, new TGLayoutHints(kLHintsTop|kLHintsLeft,0,0,0,0));
AddFrame(InputFrame, fchints);
AddFrame(PBFrame, fpbhints);
SetWindowName("GWM Event Builder");
MapSubwindows();
Resize();
MapWindow();
}
EVBMainFrame::~EVBMainFrame() {
Cleanup();
delete this;
}
void EVBMainFrame::CloseWindow() {
gApplication->Terminate();
}
void EVBMainFrame::HandleMenuSelection(int id) {
if(id == M_SAVE_CONFIG) new FileViewFrame(gClient->GetRoot(), this, MAIN_W*0.5, MAIN_H*0.25, this, M_SAVE_CONFIG);
else if(id == M_LOAD_CONFIG) new FileViewFrame(gClient->GetRoot(), this, MAIN_W*0.5, MAIN_H*0.25, this, M_LOAD_CONFIG);
else if(id == M_EXIT) CloseWindow();
}
void EVBMainFrame::DoOpenWorkdir() {
new FileViewFrame(gClient->GetRoot(), this, MAIN_W*0.5, MAIN_H*0.25, this, WORKDIR);
}
void EVBMainFrame::DoOpenSMapfile() {
new FileViewFrame(gClient->GetRoot(), this, MAIN_W*0.5, MAIN_H*0.25, this, SMAP);
}
void EVBMainFrame::DoOpenScalerfile() {
new FileViewFrame(gClient->GetRoot(), this, MAIN_W*0.5, MAIN_H*0.25, this, SCALER);
}
void EVBMainFrame::DoRun() {
DisableAllInput();
SetParameters();
int type = fTypeBox->GetSelected();
fBuilder.SetAnalysisType(type);
switch(type) {
case GWMEventBuilder::CONVERT :
{
fBuilder.Convert2RawRoot();
break;
}
case GWMEventBuilder::MERGE :
{
fBuilder.MergeROOTFiles();
break;
}
case GWMEventBuilder::CONVERT_S :
{
fBuilder.Convert2SortedRoot();
break;
}
}
EnableAllInput();
}
void EVBMainFrame::HandleTypeSelection(int box, int entry) {
fRunButton->SetState(kButtonUp);
}
bool EVBMainFrame::SetParameters() {
fBuilder.SetRunRange(fRMinField->GetIntNumber(), fRMaxField->GetIntNumber());
fBuilder.SetSlowCoincidenceWindow(fSlowWindowField->GetNumber());
fBuilder.SetBufferSize(fBufferSizeField->GetNumber());
UpdateWorkdir();
UpdateSMap();
UpdateScaler();
return true;
}
void EVBMainFrame::DisplayWorkdir(const char* dir) {
fWorkField->SetText(dir);
fBuilder.SetWorkDirectory(dir);
}
void EVBMainFrame::DisplaySMap(const char* file) {
fSMapField->SetText(file);
fBuilder.SetBoardShiftFile(file);
}
void EVBMainFrame::DisplayScaler(const char* file) {
fScalerField->SetText(file);
fBuilder.SetScalerFile(file);
}
void EVBMainFrame::SaveConfig(const char* file) {
std::string filename = file;
fBuilder.WriteConfigFile(filename);
}
void EVBMainFrame::LoadConfig(const char* file) {
std::string filename = file;
fBuilder.ReadConfigFile(filename);
fWorkField->SetText(fBuilder.GetWorkDirectory().c_str());
fSMapField->SetText(fBuilder.GetBoardShiftFile().c_str());
fScalerField->SetText(fBuilder.GetScalerFile().c_str());
fSlowWindowField->SetNumber(fBuilder.GetSlowCoincidenceWindow());
fRMaxField->SetIntNumber(fBuilder.GetRunMax());
fRMinField->SetIntNumber(fBuilder.GetRunMin());
}
void EVBMainFrame::UpdateWorkdir() {
const char* dir = fWorkField->GetText();
fBuilder.SetWorkDirectory(dir);
}
void EVBMainFrame::UpdateSMap() {
const char* file = fSMapField->GetText();
fBuilder.SetBoardShiftFile(file);
}
void EVBMainFrame::UpdateScaler() {
const char* file = fScalerField->GetText();
fBuilder.SetScalerFile(file);
}
void EVBMainFrame::RunMerge(const char* file, const char* dir) {}
void EVBMainFrame::DisableAllInput() {
fRunButton->SetState(kButtonDisabled);
fOpenWorkButton->SetState(kButtonDisabled);
fOpenSMapButton->SetState(kButtonDisabled);
fOpenScalerButton->SetState(kButtonDisabled);
fWorkField->SetState(false);
fSMapField->SetState(false);
fScalerField->SetState(false);
fTypeBox->SetEnabled(false);
fBufferSizeField->SetState(false);
fRMaxField->SetState(false);
fRMinField->SetState(false);
fSlowWindowField->SetState(false);
}
void EVBMainFrame::EnableAllInput() {
fRunButton->SetState(kButtonUp);
fOpenWorkButton->SetState(kButtonUp);
fOpenSMapButton->SetState(kButtonUp);
fOpenScalerButton->SetState(kButtonUp);
fWorkField->SetState(true);
fSMapField->SetState(true);
fScalerField->SetState(true);
fTypeBox->SetEnabled(true);
fBufferSizeField->SetState(true);
fRMaxField->SetState(true);
fRMinField->SetState(true);
fSlowWindowField->SetState(true);
}

162
src/gui/FileViewFrame.cpp Normal file
View File

@ -0,0 +1,162 @@
/*
FileViewFrame.cpp
Wrapper class on a TGTransientFrame (temporary frame assoc. with a main frame)
Designed to graphically display directories and files for selection. Takes in a type
to specify the signal pathing.
Written by G.W. McCann Sep. 2020
*/
#include "EventBuilder.h"
#include "FileViewFrame.h"
#include <TGTextBuffer.h>
#include <TGLabel.h>
#include <TTimer.h>
FileViewFrame::FileViewFrame(const TGWindow* p, const TGFrame* main, UInt_t w, UInt_t h, EVBMainFrame *parent, int type) {
fMain = new TGTransientFrame(p,main,w,h);
fMain->SetCleanup(kDeepCleanup); //delete all child frames
fMain->DontCallClose(); //Close button on window disabled
dirFlag = false;
bool rootFlag = false;
suffix = ".txt";
if(type == EVBMainFrame::WORKDIR) {
dirFlag = true;
suffix = ".NOTHING";
}
/*Layout orgainization hints*/
TGLayoutHints *fhints = new TGLayoutHints(kLHintsCenterX|kLHintsCenterY,5,5,5,5);
TGLayoutHints *thints = new TGLayoutHints(kLHintsExpandX|kLHintsCenterY,5,5,5,5);
TGLayoutHints *fchints = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY,5,5,5,5);
TGLayoutHints *lhints = new TGLayoutHints(kLHintsLeft|kLHintsTop,5,5,5,5);
TGLayoutHints *fbhints = new TGLayoutHints(kLHintsCenterX|kLHintsBottom,5,5,5,5);
/*Create object for displaying*/
fViewer = new TGListView(fMain, w, h*0.5);
Pixel_t white;
gClient->GetColorByName("white", white);
fContents = new TGFileContainer(fViewer, kSunkenFrame, white);
fContents->Connect("DoubleClicked(TGFrame*,Int_t)","FileViewFrame",this,"DoDoubleClick(TGLVEntry*,Int_t)");
/*Add in text options*/
TGVerticalFrame *NameFrame = new TGVerticalFrame(fMain, w, h*0.25);
TGLabel *nameLabel;
if(dirFlag) nameLabel = new TGLabel(NameFrame, "Dir:");
else nameLabel = new TGLabel(NameFrame, "File:");
TGTextBuffer* fNameBuffer;
fNameField = new TGTextEntry(NameFrame, fNameBuffer = new TGTextBuffer(50));
fNameField->Resize(w*0.5, fNameField->GetDefaultHeight());
NameFrame->AddFrame(nameLabel, lhints);
NameFrame->AddFrame(fNameField, thints);
/*Buttons for ok and cancel*/
TGHorizontalFrame *ButtonFrame = new TGHorizontalFrame(fMain, w, h*0.25);
fOkButton = new TGTextButton(ButtonFrame, "Ok");
fOkButton->Connect("Clicked()","FileViewFrame",this,"DoOk()");
fCancelButton = new TGTextButton(ButtonFrame, "Cancel");
fCancelButton->Connect("Clicked()","FileViewFrame",this,"DoCancel()");
ButtonFrame->AddFrame(fOkButton, fhints);
ButtonFrame->AddFrame(fCancelButton, fhints);
fMain->AddFrame(fViewer, fchints);
fMain->AddFrame(NameFrame, thints);
fMain->AddFrame(ButtonFrame, fbhints);
/*Send signal to appropriate location*/
if(type == EVBMainFrame::WORKDIR) Connect("SendText(const char*)","EVBMainFrame",parent,"DisplayWorkdir(const char*)");
else if(type == EVBMainFrame::SMAP) Connect("SendText(const char*)","EVBMainFrame",parent,"DisplaySMap(const char*)");
else if(type == EVBMainFrame::SCALER) Connect("SendText(const char*)","EVBMainFrame",parent,"DisplayScaler(const char*)");
else if(type == EVBMainFrame::M_LOAD_CONFIG) Connect("SendText(const char*)","EVBMainFrame",parent,"LoadConfig(const char*)");
else if(type == EVBMainFrame::M_SAVE_CONFIG) Connect("SendText(const char*)","EVBMainFrame",parent,"SaveConfig(const char*)");
fMain->SetWindowName("Select File");
fMain->MapSubwindows();
fMain->Resize();
fMain->CenterOnParent();
fMain->MapWindow();
fContents->SetDefaultHeaders();
if(dirFlag) fContents->SetFilter("*.NOTHING"); //relevant extension
else if(rootFlag) fContents->SetFilter("*.root");
else fContents->SetFilter("*.txt");
fContents->DisplayDirectory();
fContents->AddFile(".."); //go back a dir
fContents->Resize();
fContents->StopRefreshTimer();
fMain->Resize();
}
FileViewFrame::~FileViewFrame() {
fMain->Cleanup(); //delete children
fMain->DeleteWindow();
}
void FileViewFrame::CloseWindow() {
delete this;
}
void FileViewFrame::DoOk() {
/*Prevent user from doing something dumb*/
fOkButton->SetState(kButtonDisabled);
fCancelButton->SetState(kButtonDisabled);
TString filename = fNameField->GetText();
TString fullpath;
if(!dirFlag) fullpath = TString(fContents->GetDirectory()) + "/" + filename;
else fullpath = filename;
if(fullpath == "") { //check validity
std::cerr<<"Need to give a name!"<<std::endl;
fOkButton->SetState(kButtonUp);
fCancelButton->SetState(kButtonUp);
return;
}
SendText(fullpath.Data()); //signal sent
//Destroy this frame after a brief pause (to make sure memory isnt freed too quickly)
TTimer::SingleShot(150,"FileViewFrame",this,"CloseWindow()");
}
void FileViewFrame::DoCancel() {
/*Prevent user from doing something dumb*/
fOkButton->SetState(kButtonDisabled);
fCancelButton->SetState(kButtonDisabled);
//Destroy this frame after a brief pause (to make sure memory isnt freed too quickly)
TTimer::SingleShot(150,"FileViewFrame",this,"CloseWindow()");
}
//Handle directory selection
void FileViewFrame::DisplayDir(const TString& name) {
fContents->SetDefaultHeaders();
fContents->ChangeDirectory(name);
fContents->DisplayDirectory();
fContents->AddFile("..");
fMain->Resize();
}
//Handle double click
void FileViewFrame::DoDoubleClick(TGLVEntry *entry, int id) {
if( id != kButton1) return;
TString dirname(fContents->GetDirectory());
TString entryname(entry->GetTitle());
if(entryname.EndsWith(suffix.c_str())) { //check if its a file
TString name = entryname;
fNameField->SetText(name.Data());
} else {
DisplayDir(entryname);
if(dirFlag) {
fNameField->SetText(fContents->GetDirectory());
}
}
}
/*SIGNAL*/
void FileViewFrame::SendText(const char* text) {
Emit("SendText(const char*)", text);
}

12
src/gui_main.cpp Normal file
View File

@ -0,0 +1,12 @@
#include "EventBuilder.h"
#include <TApplication.h>
#include "EVBMainFrame.h"
int main(int argc, char** argv) {
TApplication app("app", &argc, argv);
UInt_t h = 400;
UInt_t w = 400;
EVBMainFrame* myEVB = new EVBMainFrame(gClient->GetRoot(), w, h);
app.Run();
return 0;
}

45
src/main.cpp Normal file
View File

@ -0,0 +1,45 @@
#include "EventBuilder.h"
#include "GWMEventBuilder.h"
#include "Stopwatch.h"
int main(int argc, char** argv) {
if(argc != 3) {
std::cerr<<"Incorrect number of command line arguments!"<<std::endl;
std::cerr<<"Need to specify type of operation (buildSlow, buildFast, etc.) and input file."<<std::endl;
return 1;
}
std::string filename = argv[2];
std::string operation = argv[1];
/* DEFAULT Operation Types:
convert (convert binary archive to root data)
convertSlow (convert binary arhcive to event slow data)
merge (combine root files)
*/
GWMEventBuilder theBuilder;
if(!theBuilder.ReadConfigFile(filename)) {
return 1;
}
Stopwatch timer;
timer.Start();
if(operation == "convert") {
theBuilder.SetAnalysisType(GWMEventBuilder::CONVERT);
theBuilder.Convert2RawRoot();
} else if(operation == "merge") {
theBuilder.SetAnalysisType(GWMEventBuilder::MERGE);
theBuilder.MergeROOTFiles();
} else if (operation == "convertSlow"){
theBuilder.SetAnalysisType(GWMEventBuilder::CONVERT_S);
theBuilder.Convert2SortedRoot();
} else {
std::cerr<<"Unidentified type of operation! Check your first argument."<<std::endl;
return 1;
}
timer.Stop();
std::cout<<"Elapsed time (ms): "<<timer.GetElapsedMilliseconds()<<std::endl;
return 0;
}