merge from origin master

This commit is contained in:
Calem@RAISOR 2024-09-14 17:17:00 -05:00
commit f68d26de65
53 changed files with 3662 additions and 1343 deletions

12
.gitignore vendored
View File

@ -3,6 +3,8 @@
*.root
*.bin
core.*
FSUDAQr
FSUDAQ_Qt6
test
@ -22,16 +24,20 @@ DAQLock.dat
DumpFSU2ROOT
SettingsExplorer
AggSeparator
FSU2CAEN
Bin2Root
data
splitpole.C
splitpole.h
Data
raw_binary
*.d
*.pcm
*.txt
*.tar
*.tar.gz
*.BIN
*~
*.autosave

58
.vscode/settings.json vendored
View File

@ -82,39 +82,36 @@
}
],
"files.associations": {
"mainWindow.C": "cpp",
"Scope.C": "cpp",
"new": "cpp",
"allocator": "cpp",
"array": "cpp",
"istream": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"limits": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"*.C": "cpp",
"*.pro": "makefile",
"regex": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
@ -129,38 +126,35 @@
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"format": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"variant": "cpp",
"qmainwindow": "cpp",
"qchartview": "cpp",
"qthread": "cpp",
"qrandomgenerator": "cpp",
"source_location": "cpp",
"splitpole.C": "cpp",
"forward_list": "cpp",
"fstream": "cpp",
"Analyzer.C": "cpp",
"process_Run.C": "cpp",
"EncoreAnalyzer.C": "cpp",
"qfiledialog": "cpp"
"variant": "cpp"
}
}

View File

@ -20,7 +20,7 @@ struct FileInfo{
};
#define NMINARG 5
#define NMINARG 4
#define debug 0
//^#############################################################
@ -32,14 +32,13 @@ int main(int argc, char **argv) {
printf("=========================================\n");
if (argc < NMINARG) {
printf("Incorrect number of arguments:\n");
printf("%s [timeWindow] [withTrace] [format] [inFile1] [inFile2] .... \n", argv[0]);
printf("%s [timeWindow] [withTrace] [inFile1] [inFile2] .... \n", argv[0]);
printf(" timeWindow : in ns, -1 = no event building \n");
printf(" withTrace : 0 for no trace, 1 for trace \n");
printf(" format : 0 for root, 1 for CoMPASS binary \n");
printf(" Output file name is contructed from inFile1 \n");
printf("\n");
printf(" Example: %s -1 0 0 '\\ls -1 *001*.fsu' (no event build, no trace, no verbose)\n", argv[0]);
printf(" %s 100 0 0 '\\ls -1 *001*.fsu' (event build with 100 ns, no trace, no verbose)\n", argv[0]);
printf(" Example: %s -1 0 '\\ls -1 *001*.fsu' (no event build, no trace, no verbose)\n", argv[0]);
printf(" %s 100 0 '\\ls -1 *001*.fsu' (event build with 100 ns, no trace, no verbose)\n", argv[0]);
printf("\n\n");
return 1;
@ -51,7 +50,7 @@ int main(int argc, char **argv) {
long timeWindow = atoi(argv[1]);
bool traceOn = atoi(argv[2]);
// unsigned int debug = atoi(argv[3]);
unsigned short format = atoi(argv[3]);
// unsigned short format = atoi(argv[3]);
unsigned int batchSize = 2* DEFAULT_HALFBUFFERSIZE;
int nFile = argc - NMINARG + 1;
TString inFileName[nFile];
@ -67,13 +66,9 @@ int main(int argc, char **argv) {
outFileName += "_" + ( timeWindow >= 0 ? std::to_string(timeWindow) : "single");
TString outFileFullName;
if( format == 0 ){
outFileFullName = outFileName + ".root";
}else{
outFileFullName = outFileName + ".bin";
}
outFileFullName = outFileName + ".root";
uint16_t header = 0; // for caen bin
// uint16_t header = 0; // for caen bin
printf("-------> Out file name : %s \n", outFileFullName.Data());
printf("========================================= Number of Files : %d \n", nFile);
@ -94,6 +89,8 @@ int main(int argc, char **argv) {
FSUReader * readerA = new FSUReader(inFileName[0].Data(), 1, 1);
readerA->ScanNumBlock(0,0);
if( readerA->GetOptimumBatchSize() > batchSize ) batchSize = readerA->GetOptimumBatchSize();
//printf("Hit count : %7ld | opt. batch size : %7ld\n", readerA->GetTotalHitCount(), readerA->GetOptimumBatchSize());
FileInfo fileInfo = {inFileName[0].Data(), readerA->GetSN() * 1000 + readerA->GetFileOrder(), readerA->GetTotalHitCount()};
fileList.push_back(fileInfo);
totalHitCount += readerA->GetTotalHitCount();
@ -101,7 +98,9 @@ int main(int argc, char **argv) {
for( int i = 1; i < nFile; i++){
FSUReader * readerB = new FSUReader(inFileName[i].Data(), 1, 1);
readerB->ScanNumBlock(0,0);
if( readerB->GetOptimumBatchSize() > batchSize ) batchSize = readerB->GetOptimumBatchSize();
// if( readerB->GetOptimumBatchSize() > batchSize ) batchSize = readerB->GetOptimumBatchSize();
batchSize = readerB->GetOptimumBatchSize();
//printf("Hit count : %7ld | opt. batch size : %7ld\n", readerB->GetTotalHitCount(), readerB->GetOptimumBatchSize());
totalHitCount += readerB->GetTotalHitCount();
fileInfo = {inFileName[i].Data(), readerB->GetSN() * 1000 + readerB->GetFileOrder(), readerB->GetTotalHitCount()};
@ -147,39 +146,27 @@ int main(int argc, char **argv) {
unsigned short traceLength[MAX_MULTI];
short trace[MAX_MULTI][MAX_TRACE_LENGTH];
FILE * caen = nullptr;
// //*====================================== create tree
outRootFile = new TFile(outFileFullName, "recreate");
tree = new TTree("tree", outFileFullName);
if( format == 0 ){
// //*====================================== create tree
outRootFile = new TFile(outFileFullName, "recreate");
tree = new TTree("tree", outFileFullName);
tree->Branch("evID", &evID, "event_ID/l");
tree->Branch("multi", &multi, "multi/i");
tree->Branch("sn", sn, "sn[multi]/s");
tree->Branch("ch", ch, "ch[multi]/s");
tree->Branch("e", e, "e[multi]/s");
tree->Branch("e2", e2, "e2[multi]/s");
tree->Branch("e_t", e_t, "e_t[multi]/l");
tree->Branch("e_f", e_f, "e_f[multi]/s");
tree->Branch("traceLength", traceLength, "traceLength[multi]/s");
if( traceOn ) {
tree->Branch("trace", trace,"trace[multi][MAX_TRACE_LENGTH]/S");
tree->GetBranch("trace")->SetCompressionSettings(205);
}
}else{
caen = fopen(outFileFullName.Data(), "wb");
if( caen == nullptr ){
perror("Failed to open file");
return -1;
}
tree->Branch("evID", &evID, "event_ID/l");
tree->Branch("multi", &multi, "multi/i");
tree->Branch("sn", sn, "sn[multi]/s");
tree->Branch("ch", ch, "ch[multi]/s");
tree->Branch("e", e, "e[multi]/s");
tree->Branch("e2", e2, "e2[multi]/s");
tree->Branch("e_t", e_t, "e_t[multi]/l");
tree->Branch("e_f", e_f, "e_f[multi]/s");
tree->Branch("traceLength", traceLength, "traceLength[multi]/s");
if( traceOn ) {
tree->Branch("trace", trace,"trace[multi][MAX_TRACE_LENGTH]/S");
tree->GetBranch("trace")->SetCompressionSettings(205);
}
//*======================================= Open files
printf("========================================= Open files & Build Events.\n");
printf("========================================= Open files & reading 1st batch.\n");
const short nGroup = fileGroupList.size();
std::vector<Hit> hitList[nGroup];
@ -192,7 +179,7 @@ int main(int argc, char **argv) {
fList.push_back( fileGroupList[i][j].fileName );
}
reader[i] = new FSUReader(fList, 1024, debug); // 1024 is the maximum event / agg.
hitList[i] = reader[i]->ReadBatch(batchSize, debug );
hitList[i] = reader[i]->ReadBatch(batchSize, traceOn, debug );
reader[i]->PrintHitListInfo(&hitList[i], "hitList-" + std::to_string(reader[i]->GetSN()));
ID[i] = 0;
if( debug ) {
@ -227,6 +214,7 @@ int main(int argc, char **argv) {
std::vector<Hit> events;
unsigned long long hitProcessed = 0;
printf("========================================= Start Building Events....\n");
do{
@ -241,7 +229,7 @@ int main(int argc, char **argv) {
//chekc if reached the end of hitList
if( ID[ig] >= hitList[ig].size() ) {
hitList[ig] = reader[ig]->ReadBatch(batchSize, debug + 1);
hitList[ig] = reader[ig]->ReadBatch(batchSize, traceOn, debug + 1);
if( debug ) reader[ig]->PrintHitListInfo( &hitList[ig], "hitList-" + std::to_string(ig));
ID[ig] = 0;
if( hitList[ig].size() == 0 ) continue;
@ -251,8 +239,8 @@ int main(int argc, char **argv) {
do{
if( (long int)(hitList[ig].at(ID[ig]).timestamp - t0) <= timeWindow ){
events.push_back(hitList[ig].at(ID[ig]));
if( (long int)(hitList[ig][ID[ig]].timestamp - t0) <= timeWindow ){
events.push_back(hitList[ig][ID[ig]]);
ID[ig] ++;
}else{
break;
@ -260,7 +248,7 @@ int main(int argc, char **argv) {
//check if reached the end of hitList
if( ID[ig] >= hitList[ig].size() ) {
hitList[ig] = reader[ig]->ReadBatch(batchSize, debug);
hitList[ig] = reader[ig]->ReadBatch(batchSize, traceOn, debug);
if( debug ) reader[ig]->PrintHitListInfo( &hitList[ig], "hitList-" + std::to_string(ig));
ID[ig] = 0;
if( hitList[ig].size() == 0 ) break;
@ -291,6 +279,9 @@ int main(int argc, char **argv) {
multi = events.size() ;
if( events.size() >= MAX_MULTI ) {
printf("\033[31m event %lld has size = %d > MAX_MULTI = %d \033[0m\n", evID, multi, MAX_MULTI);
for( int po = 0 ; po < 10 ; po ++){
events[po].Print();
}
multi = MAX_MULTI;
}
if( debug ) printf("=================================== filling data | %u \n", multi);
@ -318,27 +309,10 @@ int main(int argc, char **argv) {
}
}
if( format == 0 ){
outRootFile->cd();
tree->Fill();
// tree->Write();
}else{
if( caen ) {
if( header == 0 ){
header = 0xCAE1; // default to have the energy only
if( events[0].energy2 > 0 ) header += 0x4;
if( events[0].traceLength > 0 && traceOn ) header += 0x8;
size_t dummy = fwrite(&header, 2, 1, caen);
if( dummy != 1 ) printf("file write error.\n");
}
for( size_t gg = 0; gg < events.size(); gg++ ){
events[gg].WriteHitsToCAENBinary(caen, header);
}
}
}
outRootFile->cd();
tree->Fill();
// tree->Write();
multi = 0;
evID ++;
@ -363,7 +337,7 @@ int main(int argc, char **argv) {
continue;
}else{
if( ID[i] >= hitList[i].size( )) {
hitList[i] = reader[i]->ReadBatch(batchSize, debug);
hitList[i] = reader[i]->ReadBatch(batchSize, traceOn, debug);
ID[i] = 0;
if( hitList[i].size() == 0 ) nFileFinished ++;
}
@ -373,7 +347,7 @@ int main(int argc, char **argv) {
}while( nFileFinished < nGroup);
if( format == 0 ) tree->Write();
tree->Write();
uInt runEndTime = getTime_us();
double runTime = (runEndTime - runStartTime) * 1e-6;
@ -387,15 +361,12 @@ int main(int argc, char **argv) {
printf(" total data duration = %.2f sec = %.2f min\n", tDuration_sec, tDuration_sec/60.);
printf("========================================> saved to %s \n", outFileFullName.Data());
if( format == 0 ){
TMacro info;
info.AddLine(Form("tStart= %20llu ns",tStart));
info.AddLine(Form(" tEnd= %20llu ns",tEnd));
info.Write("info");
outRootFile->Close();
}else{
fclose(caen);
}
TMacro info;
info.AddLine(Form("tStart= %20llu ns",tStart));
info.AddLine(Form(" tEnd= %20llu ns",tEnd));
info.Write("info");
outRootFile->Close();
for( int i = 0; i < nGroup; i++) delete reader[i];
delete [] reader;

305
Aux/FSU2CAEN.cpp Normal file
View File

@ -0,0 +1,305 @@
#include "fsuReader.h"
struct FileInfo{
std::string fileName;
int fileevID;
unsigned long hitCount;
int sn;
int numCh;
int runNum;
};
#define minNARG 3
//^#############################################################
//^#############################################################
int main(int argc, char **argv) {
printf("=========================================\n");
printf("=== *.fsu to CoMPASS bin ===\n");
printf("=========================================\n");
if (argc < minNARG) {
printf("Incorrect number of arguments:\n");
printf("%s [tar] [inFile1] [inFile2] .... \n", argv[0]);
printf(" tar : output tar, 0 = no, 1 = yes \n");
printf("\n");
printf(" Example: %s 0 '\\ls -1 *001*.fsu'\n", argv[0]);
printf("\n\n");
return 1;
}
unsigned int debug = false;
uInt runStartTime = getTime_us();
///============= read input
// long timeWindow = atoi(argv[1]);
// bool traceOn = atoi(argv[2]);
bool tarFlag = atoi(argv[1]);
unsigned int batchSize = 2* DEFAULT_HALFBUFFERSIZE;
int nFile = argc - minNARG + 1;
std::string inFileName[nFile];
for( int i = 0 ; i < nFile ; i++){ inFileName[i] = argv[i+ minNARG - 1];}
printf("========================================= Number of Files : %d \n", nFile);
for( int i = 0; i < nFile; i++) printf("%2d | %s \n", i, inFileName[i].c_str());
printf("=========================================\n");
printf(" Batch size = %d events/file\n", batchSize);
// printf(" Out file name = %s \n", outFileName.c_str());
printf(" Is tar output = %s \n", tarFlag ? "Yes" : "No");
printf("========================================= Grouping files\n");
std::vector<std::vector<FileInfo>> fileGroupList; // fileName and evID = SN * 1000 + index
std::vector<FileInfo> fileList;
unsigned long long int totalHitCount = 0;
FSUReader * readerA = new FSUReader(inFileName[0], 1, 1);
readerA->ScanNumBlock(0,0);
if( readerA->GetOptimumBatchSize() > batchSize ) batchSize = readerA->GetOptimumBatchSize();
FileInfo fileInfo = {inFileName[0], readerA->GetSN() * 1000 + readerA->GetFileOrder(), readerA->GetTotalHitCount(), readerA->GetSN(), readerA->GetNumCh(), readerA->GetRunNum()};
fileList.push_back(fileInfo);
totalHitCount += readerA->GetTotalHitCount();
for( int i = 1; i < nFile; i++){
FSUReader * readerB = new FSUReader(inFileName[i], 1, 1);
readerB->ScanNumBlock(0,0);
if( readerB->GetOptimumBatchSize() > batchSize ) batchSize = readerB->GetOptimumBatchSize();
totalHitCount += readerB->GetTotalHitCount();
fileInfo = {inFileName[i], readerB->GetSN() * 1000 + readerB->GetFileOrder(), readerB->GetTotalHitCount(), readerB->GetSN(), readerB->GetNumCh(), readerB->GetRunNum()};
if( readerA->GetSN() == readerB->GetSN() ){
fileList.push_back(fileInfo);
}else{
fileGroupList.push_back(fileList);
fileList.clear();
fileList.push_back(fileInfo);
}
delete readerA;
readerA = readerB;
}
fileGroupList.push_back(fileList);
delete readerA;
printf("======================= total Hit Count : %llu\n", totalHitCount);
for( size_t i = 0; i < fileGroupList.size(); i++){
printf("group ----- %ld \n", i);
//sort by evID
std::sort(fileGroupList[i].begin(), fileGroupList[i].end(), [](const FileInfo & a, const FileInfo & b) {
return a.fileevID < b.fileevID;
});
for( size_t j = 0; j < fileGroupList[i].size(); j++){
printf("%3ld | %8d | %9lu| %s \n", j, fileGroupList[i][j].fileevID, fileGroupList[i][j].hitCount, fileGroupList[i][j].fileName.c_str() );
}
}
//*====================================== format output files
const short numFileGroup = fileGroupList.size();
FILE ** outFile[numFileGroup];
std::vector<std::string> outFileName[numFileGroup];
std::vector<uint16_t> header[numFileGroup];
std::vector<unsigned int> flags[numFileGroup];
for( int i = 0; i < numFileGroup; i++ ){
outFile[i] = new FILE * [fileGroupList[i][0].numCh];
for( int ch = 0; ch < fileGroupList[i][0].numCh; ch++ ){
std::string dudu = "Data_CH" + std::to_string(ch) + "@DIGI_" + std::to_string(fileGroupList[i][0].sn) + "_run_" + std::to_string(fileGroupList[i][0].runNum) + ".BIN";
// printf("|%s| \n", dudu.c_str());
outFile[i][ch] = fopen(dudu.c_str(), "wb");
outFileName[i].push_back(dudu);
header[i].push_back(0);
flags[i].push_back(0);
}
}
// std::string temp = inFileName[0];
// size_t pos = temp.find('_');
// pos = temp.find('_', pos + 1);
// std::string outFile_prefix = temp.substr(0, pos);
// std::string outFileName = outFile_prefix + ".BIN";
//*======================================= Open files
printf("========================================= Open files & Build Events.\n");
const short nGroup = fileGroupList.size();
std::vector<Hit> hitList[nGroup];
FSUReader ** reader = new FSUReader * [nGroup];
ulong evID[nGroup];
for( short i = 0; i < nGroup; i++){
std::vector<std::string> fList;
for( size_t j = 0; j < fileGroupList[i].size(); j++){
fList.push_back( fileGroupList[i][j].fileName );
}
reader[i] = new FSUReader(fList, 600, debug);
hitList[i] = reader[i]->ReadBatch(batchSize, debug );
reader[i]->PrintHitListInfo(&hitList[i], "hitList-" + std::to_string(reader[i]->GetSN()));
evID[i] = 0;
if( debug ) {
for( size_t p = 0; p < 10; p ++ ){
if( hitList[i].size() <= p ) break;
hitList[i][p].Print();
}
}
}
unsigned long long tStart = 0;
unsigned long long tEnd = 0;
unsigned long long t0 = -1;
short g0 = 0 ;
int nFileFinished = 0;
unsigned long long hitProcessed = 0;
do{
// find the earlist time
t0 = -1;
for( short i = 0; i < nGroup; i++){
if( hitList[i].size() == 0 ) continue;
//chekc if reached the end of hitList
if( evID[i] >= hitList[i].size() ) {
hitList[i] = reader[i]->ReadBatch(batchSize, debug + 1);
if( debug ) reader[i]->PrintHitListInfo( &hitList[i], "hitList-" + std::to_string(i));
evID[i] = 0;
if( hitList[i].size() == 0 ) continue;
}
if( hitList[i][evID[i]].timestamp < t0 ) {
t0 = hitList[i][evID[i]].timestamp;
g0 = i;
}
}
// Set file header
int p_ch = hitList[g0][evID[g0]].ch; // present ch
if( header[g0][p_ch] == 0 ) {
header[g0][p_ch] = 0xCAE1;
if( hitList[g0][evID[g0]].energy2 > 0 ) header[g0][p_ch] += 4;
if( hitList[g0][evID[g0]].traceLength > 0 ) header[g0][p_ch] += 8;
if( hitList[g0][evID[g0]].pileUp ) flags[g0][p_ch] += 0x8000;
if( hitList[g0][evID[g0]].fineTime > 0 ) flags[g0][p_ch] += 0x4000;
fwrite(&(header[g0][p_ch]), 2, 1, outFile[g0][p_ch]);
}
hitList[g0][evID[g0]].WriteHitsToCAENBinary(outFile[g0][p_ch], header[g0][p_ch]);
// fwrite(&(hitList[g0][evID[g0]].sn), 2, 1, outFile);
// fwrite(&(hitList[g0][evID[g0]].ch), 2, 1, outFile);
// unsigned psTimestamp = hitList[g0][evID[g0]].timestamp * 1000 + hitList[g0][evID[g0]].fineTime;
// fwrite(&(psTimestamp), 8, 1, outFile);
// fwrite(&(hitList[g0][evID[g0]].energy), 2, 1, outFile);
// if( hitList[g0][evID[g0]].energy2 > 0 ) fwrite(&(hitList[g0][evID[g0]].energy2), 2, 1, outFile);
// fwrite(&(flags), 4, 1, outFile);
// if( hitList[g0][evID[g0]].traceLength > 0 ){
// char waveCode = 1;
// fwrite(&(waveCode), 1, 1, outFile);
// fwrite(&(hitList[g0][evID[g0]].traceLength), 4, 1, outFile);
// for( int i = 0; i < hitList[g0][evID[g0]].traceLength; i++ ){
// fwrite(&(hitList[g0][evID[g0]].trace[i]), 2, 1, outFile);
// }
// }
evID[g0]++;
if( hitProcessed == 0) tStart = hitList[g0][evID[g0]].timestamp;
hitProcessed ++;
if( hitProcessed % 10000 == 0 ) printf("hit Porcessed %llu/%llu hit....%.2f%%\n\033[A\r", hitProcessed, totalHitCount, hitProcessed*100./totalHitCount);
if( hitProcessed == totalHitCount -1 ) tEnd = hitList[g0][evID[g0]].timestamp;
//*=============
nFileFinished = 0;
for( int i = 0 ; i < nGroup; i++) {
if( hitList[i].size() == 0 ) {
nFileFinished ++;
continue;
}else{
if( evID[i] >= hitList[i].size( )) {
hitList[i] = reader[i]->ReadBatch(batchSize, debug);
evID[i] = 0;
if( hitList[i].size() == 0 ) nFileFinished ++;
}
}
}
if( debug > 1 ) printf("========== nFileFinished : %d\n", nFileFinished);
}while( nFileFinished < nGroup);
uInt runEndTime = getTime_us();
double runTime = (runEndTime - runStartTime) * 1e-6;
printf("========================================= finished.\n");
printf(" event building time = %.2f sec = %.2f min\n", runTime, runTime/60.);
printf(" total hit = %llu \n", hitProcessed);
double tDuration_sec = (tEnd - tStart) * 1e-9;
printf(" first timestamp = %20llu ns\n", tStart);
printf(" last timestamp = %20llu ns\n", tEnd);
printf(" total data duration = %.2f sec = %.2f min\n", tDuration_sec, tDuration_sec/60.);
for( int i = 0; i < nGroup; i++) delete reader[i];
delete [] reader;
//============================== delete empty files and close FILE
std::vector<std::string> nonEmptyFileList;
printf("================= Removing Empty Files ....\n");
printf("============================> saved to ....");
if( tarFlag == false ) printf("\n");
for( int i = 0; i < numFileGroup; i++ ){
for( int ch = 0; ch < fileGroupList[i][0].numCh; ch++){
if( ftell(outFile[i][ch]) == 0 ){
int dummy = std::system(("rm -f " + outFileName[i][ch]).c_str());
// printf("Remove %s.\n", outFileName[i][ch].c_str());
}else{
nonEmptyFileList.push_back(outFileName[i][ch]);
if( tarFlag == false ) printf("%s\n", outFileName[i][ch].c_str());
}
}
}
if( tarFlag ){
std::string tarFileName = "run_" + std::to_string(fileGroupList[0][0].runNum) + ".tar.gz";
printf("%s\n", tarFileName.c_str());
printf("============================> tar.gz the BIN\n");
std::string command = "tar -czf " + tarFileName + " ";
for( size_t i = 0; i < nonEmptyFileList.size(); i++ ){
command += nonEmptyFileList[i] + " ";
}
int result = std::system(command.c_str());
if (result == 0) {
printf("Archive created successfully: %s\n", tarFileName.c_str());
for( size_t i = 0; i < nonEmptyFileList.size(); i++ ){
int dummy = std::system(("rm -f " + nonEmptyFileList[i]).c_str());
// printf("Remove %s.\n", nonEmptyFileList[i].c_str());
}
} else {
printf("Error creating archive\n");
}
}
printf("============================================== end of program\n");
return 0;
}

View File

@ -5,8 +5,8 @@
CC = g++
#COPTS = -fPIC -DLINUX -O2 -std=c++17 -lpthread
COPTS = -fPIC -DLINUX -g -O0 -Wall -std=c++17 -lpthread
COPTS = -fPIC -DLINUX -O2 -std=c++17 -lpthread
# COPTS = -fPIC -DLINUX -g -O0 -Wall -std=c++17 -lpthread
CAENLIBS = -lCAENDigitizer -lCAENVME
@ -14,7 +14,7 @@ ROOTLIBS = `root-config --cflags --glibs`
OBJS = ClassDigitizer.o MultiBuilder.o ClassInfluxDB.o
ALL = test EventBuilder DataReader DumpFSU2ROOT SettingsExplorer
ALL = test EventBuilder DataReader DumpFSU2ROOT SettingsExplorer FSU2CAEN
#########################################################################
@ -34,7 +34,7 @@ ClassInfluxDB.o : ../ClassInfluxDB.cpp ../ClassInfluxDB.h
test : test.cpp ../ClassDigitizer.o ../MultiBuilder.o ../ClassInfluxDB.o
@echo "--------- making test"
$(CC) $(COPTS) -o test test.cpp ../ClassDigitizer.o ../MultiBuilder.o ../ClassInfluxDB.o $(CAENLIBS) $(ROOTLIBS) -lcurl
$(CC) -fPIC -DLINUX -O0 -std=c++17 -lpthread -g -o test test.cpp ../ClassDigitizer.o ../MultiBuilder.o ../ClassInfluxDB.o $(CAENLIBS) $(ROOTLIBS) -lcurl
# test_indep : test_indep.cpp ../RegisterAddress.h ../macro.h
# @echo "--------- making test_indep"
@ -44,17 +44,13 @@ DataReader : DataReaderScript.cpp ../ClassData.h MultiBuilder.o
@echo "--------- making DataReader"
$(CC) $(COPTS) -o DataReader DataReaderScript.cpp ../ClassData.h MultiBuilder.o
# EventBuilder_old : EventBuilder_old.cpp ../ClassData.h MultiBuilder.o fsuReader.h
# @echo "--------- making EventBuilder"
# $(CC) $(COPTS) -o EventBuilder_old EventBuilder_old.cpp MultiBuilder.o $(ROOTLIBS)
EventBuilder : EventBuilder.cpp ../ClassData.h fsuReader.h ../Hit.h
@echo "--------- making EventBuilder"
$(CC) $(COPTS) -o EventBuilder EventBuilder.cpp $(ROOTLIBS)
# EventBuilderNoTrace : EventBuilderNoTrace.cpp ../ClassData.h fsuReader.h ../Hit.h
# @echo "--------- making EventBuilderNoTrace"
# $(CC) $(COPTS) -o EventBuilderNoTrace EventBuilderNoTrace.cpp $(ROOTLIBS)
FSU2CAEN : FSU2CAEN.cpp ../ClassData.h fsuReader.h ../Hit.h
@echo "--------- making FSU2CAEN"
$(CC) $(COPTS) -o FSU2CAEN FSU2CAEN.cpp
DumpFSU2ROOT : DumpFSU2ROOT.cpp ../ClassData.h MultiBuilder.o
@echo "--------- making DumpFSU2ROOT"

View File

@ -37,18 +37,16 @@ With this approach, it is guaranteed that the output hitList_A is always time-so
This defines the EventBuilder. The arguments are
```sh
./EventBuilder [timeWindow] [withTrace] [verbose] [batchSize] [inFile1] [inFile2] ....
./EventBuilder [timeWindow] [withTrace] [inFile1] [inFile2] ....
timeWindow : in ns, -1 = no event building
withTrace : 0 for no trace, 1 for trace
verbose : > 0 for debug
batchSize : the size of hit in a batch
Output file name is contructed from inFile1
```
as an example,
```sh
/EventBuilder 0 0 0 1000000 '\ls -1 test_001*.fsu'
/EventBuilder 0 0'\ls -1 test_001*.fsu'
```
setting the timeWindow to be -1, will split out a timesorted Hit.
@ -115,6 +113,16 @@ Evenbuilder output is standard information, an example structure is
*............................................................................*
```
# FSU2CAEN.cpp
This convert the *.fsu to Data_CHXX@DIGI_YYYYY_run_ZZ.BIN. the BIN is CoMPASS format and could be useful for couple with existing analysis routine.
```sh
./FSU2CAEN [tarFlag] [inFile1] [inFile2] ....
targFlag : if 1, tar ball all output files.
```
# SettingsExplorer.cpp

View File

@ -64,13 +64,14 @@ void keyPressCommand(){
if( RegList[i].GetRWType() == RW::ReadONLY ) typeStr = "R ";
if( RegList[i].GetRWType() == RW::WriteONLY ) typeStr = " W";
unsigned int value = digi->GetSettingFromMemory(RegList[i], 0);
printf("%2d | 0x%04X %30s %s 0x%08X = %u\n", i,
printf("%2d | 0x%04X %30s %s 0x%08X = %10u\n", i,
RegList[i].GetAddress(),
RegList[i].GetNameChar(),
typeStr.c_str(),
digi->GetSettingFromMemory(RegList[i], 0),
digi->GetSettingFromMemory(RegList[i], 0));
value,
value);
}
std::string input = "-1";
@ -143,12 +144,15 @@ void keyPressCommand(){
RegList[i].ActualAddress(ch);
printf("%2d | 0x%04X %30s %s 0x%08X = %u\n", i,
unsigned int value = digi->GetSettingFromMemory(RegList[i], ch);
printf("%2d | 0x%04X %30s %s 0x%08X = %10u : %d\n", i,
RegList[i].GetAddress(),
RegList[i].GetNameChar(),
typeStr.c_str(),
digi->GetSettingFromMemory(RegList[i], ch),
digi->GetSettingFromMemory(RegList[i], ch));
value,
value,
value * abs(RegList[i].GetPartialStep()));
}
do{

274
Aux/SplitPolePlotter.C Normal file
View File

@ -0,0 +1,274 @@
#ifndef SPLITPOLEPLOTTER
#define SPLITPOLEPLOTTER
#include "TFile.h"
#include "TChain.h"
#include "TH1F.h"
#include "TTreeReader.h"
#include "TTreeReaderValue.h"
#include "TTreeReaderArray.h"
#include "TClonesArray.h"
#include "TGraph.h"
#include "TCutG.h"
#include "TH2.h"
#include "TCanvas.h"
#include "TStyle.h"
#include "TStopwatch.h"
#include "TMath.h"
#include "vector"
#include "../analyzers/SplitPoleHit.h"
namespace ChMap{
const short ScinR = 0;
const short ScinL = 1;
const short dFR = 9;
const short dFL = 8;
const short dBR = 11;
const short dBL = 10;
const short Cathode = 7;
const short AnodeF = 13;
const short AnodeB = 15;
};
const double c = 299.792458; // mm/ns
const double pi = M_PI;
const double deg2rad = pi/180.;
SplitPoleHit hit;
TH2F * PID;
TH2F * coin;
TH1F * hMulti;
TH1F * hF;
TH1F * hB;
TH1F * hXavg;
TH2F * hFocal;
TH2F * hXavg_Q;
TH2F * hXavg_Theta;
TH2F * hRay;
TH1F * hEx;
TH2F * hEx_Multi;
ULong64_t t1, t2;
#define XMIN -200
#define XMAX 200
//^###########################################
void SplitPolePlotter(TChain *tree, TCutG * pidCut = nullptr, double rhoOffset = 0, double rhoScaling = 1, bool isFSUDAQ = true){
printf("#####################################################################\n");
printf("################# SplitPolePlotter.C ####################\n");
printf("#####################################################################\n");
TObjArray * fileList = tree->GetListOfFiles();
printf("\033[0;31m========================================== Number of Files : %2d\n",fileList->GetEntries());
fileList->Print();
printf("========================================== Number of Files : %2d\033[0m\n",fileList->GetEntries());
printf("///////////////////////////////////////////////////////////////////\n");
printf(" Total Number of entries : %llu \n", tree->GetEntries());
printf("///////////////////////////////////////////////////////////////////\n");
if( tree->GetEntries() == 0 ) {
printf("========= no events. Abort.\n");
return;
}
//*====================================================== histograms
coin = new TH2F("hCoin", "Coincident ", 16, 0, 16, 16, 0, 16);
hMulti = new TH1F("hMulti", "Multiplicity", 16, 0, 16);
if( isFSUDAQ ){
PID = new TH2F("hPID", "PID; Scin_X ; AnodeB", 200, 0, 20000, 100, 0, 40000);
hXavg_Q = new TH2F("hXavg_Q", "Xavg vs Q ", 200, XMIN, XMAX, 200, 0, 40000);
}else{
PID = new TH2F("hPID", "PID; Scin_X ; AnodeB", 200, 0, 4000, 100, 0, 5000);
hXavg_Q = new TH2F("hXavg_Q", "Xavg vs Q ", 200, XMIN, XMAX, 200, 0, 5000);
}
hF = new TH1F("hF", "Front delay line position", 600, XMIN, XMAX);
hB = new TH1F("hB", "Back delay line position", 600, XMIN, XMAX);
hXavg = new TH1F("hAvg", "Xavg", 600, XMIN, XMAX);
hFocal = new TH2F("hFocal", "Front vs Back ", 200, XMIN, XMAX, 200, XMIN, XMAX);
hXavg_Theta = new TH2F("hXavg_Theta", "Xavg vs Theta ", 200, XMIN, XMAX, 200, 0.5, 1.4);
hRay = new TH2F("hRay", "Ray plot", 400, XMIN, XMAX, 400, -50, 50);
hEx = new TH1F("hEx", "Ex; Ex [MeV]; count/10 keV", 600, -1, 5);
hEx_Multi = new TH2F("hEx_Multi", "Ex vs Multi; Ex; Multi", 600, -1, 5, 16, 0, 16);
hit.SetMassTablePath("../analyzers/mass20.txt");
hit.CalConstants("12C", "d", "p", 16, 18); // 80MeV, 5 deg
hit.CalZoffset(0.750); // 1.41 T
t1 = 0;
t2 = 0;
//*====================================================== Tree Reader
TTreeReader reader(tree);
TTreeReaderValue<ULong64_t> evID = {reader, "evID"};
TTreeReaderValue<UInt_t> multi = {reader, "multi"};
TTreeReaderArray<UShort_t> sn = {reader, "sn"};
TTreeReaderArray<UShort_t> ch = {reader, "ch"};
TTreeReaderArray<UShort_t> e = {reader, "e"};
TTreeReaderArray<UShort_t> e2 = {reader, "e2"};
TTreeReaderArray<ULong64_t> e_t = {reader, "e_t"};
TTreeReaderArray<UShort_t> e_f = {reader, "e_f"};
ULong64_t NumEntries = tree->GetEntries();
//^###########################################################
//^ * Process
//^###########################################################
printf("############################################### Processing...\n");
fflush(stdout); // flush out any printf
ULong64_t processedEntries = 0;
float Frac = 0.1;
TStopwatch StpWatch;
StpWatch.Start();
while (reader.Next()) {
// if( processedEntries > 10 ) break;
// printf("============== %5llu | multi : %d (%zu) \n", processedEntries, multi.Get()[0], sn.GetSize());
// for( int i = 0; i < multi.Get()[0]; i++ ){
// printf(" %d | %5d %2d %7d %10llu\n", i, sn[i], ch[i], e[i], e_t[i]);
// }
hit.ClearData();
hMulti->Fill(*multi);
// if( *multi != 9 ) continue;
for( int i = 0; i < *multi; i++){
t2 = e_t[i];
if( t2 < t1 ) printf("entry %lld-%d, timestamp is not in order. %llu, %llu\n", processedEntries, i, t2, t1);
if( i == 0 ) t1 = e_t[i];
// if( e[i] == 65535 ) continue;
if( ch[i] == ChMap::ScinR ) {hit.eSR = e[i]; hit.tSR = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::ScinL ) {hit.eSL = e[i]; hit.tSL = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::dFR ) {hit.eFR = e[i]; hit.tFR = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::dFL ) {hit.eFL = e[i]; hit.tFL = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::dBR ) {hit.eBR = e[i]; hit.tBR = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::dBL ) {hit.eBL = e[i]; hit.tBL = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::Cathode ) {hit.eCath = e[i]; hit.tCath = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::AnodeF ) {hit.eAF = e[i]; hit.tAF = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::AnodeB ) {hit.eAB = e[i]; hit.tAB = e_t[i] + e_f[i]/1000;}
for( int j = i+1; j < sn.GetSize(); j++){
coin->Fill(ch[i], ch[j]);
}
}
unsigned int dQ = hit.eAB; // delta Q
unsigned int Qt = hit.eSL; // total Q
if( Qt > 0 && dQ > 0 ) {
PID->Fill(Qt, dQ);
}
//=============== PID gate cut
if( pidCut ){
if( !pidCut->IsInside(Qt, dQ) ) continue;
}
hit.CalData(2);
if( hit.theta > 1.2 || 0.5 > hit.theta ) continue;
if( (!TMath::IsNaN(hit.x1) || !TMath::IsNaN(hit.x2)) ) {
hFocal->Fill(hit.x1, hit.x2);
hF->Fill(hit.x1);
hB->Fill(hit.x2);
hXavg->Fill(hit.xAvg);
hXavg_Q->Fill(hit.xAvg, dQ);
hXavg_Theta->Fill( hit.xAvg, hit.theta);
for( int i = 0; i < 400; i++){
double z = -50 + 100/400.*i;
double x = (z/42.8625 + 0.5)* ( hit.x2-hit.x1) + hit.x1;
hRay->Fill(x,z);
}
double ex = hit.Rho2Ex( ((hit.xAvg - rhoOffset)/1000/rhoScaling + hit.GetRho0() ) );
//if( XMIN < hit.xAvg && hit.xAvg < XMAX) printf("x1 : %6.2f, x2 : %6.2f, xAvg %6.2f cm , ex : %f \n", hit.x1, hit.x2, hit.xAvg, ex);
hEx->Fill(ex);
hEx_Multi->Fill(ex, *multi);
}
//*============================================ Progress Bar
processedEntries ++;
if (processedEntries >= NumEntries*Frac - 1 ) {
TString msg; msg.Form("%llu", NumEntries/1000);
int len = msg.Sizeof();
printf(" %3.0f%% (%*llu/%llu k) processed in %6.1f sec | expect %6.1f sec\n",
Frac*100, len, processedEntries/1000,NumEntries/1000,StpWatch.RealTime(), StpWatch.RealTime()/Frac);
fflush(stdout);
StpWatch.Start(kFALSE);
Frac += 0.1;
}
}
//^###########################################################
//^ * Plot
//^###########################################################
TCanvas * canvas = new TCanvas("cc", "Split-Pole", 2500, 1000);
gStyle->SetOptStat("neiou");
canvas->Divide(5, 2);
canvas->cd(1); {
PID->Draw("colz");
if( pidCut ) pidCut->Draw("same");
}
canvas->cd(2); hRay->Draw("colz");
canvas->cd(3); hF->Draw();
canvas->cd(4); hB->Draw();
canvas->cd(5); hXavg_Q->Draw("colz");
canvas->cd(6); hXavg->Draw("colz");
canvas->cd(7); hEx->Draw();
//canvas->cd(8); coin->Draw("colz");
canvas->cd(8); hEx_Multi->Draw("colz");
canvas->cd(9); canvas->cd(9)->SetLogy(); hMulti->Draw();
canvas->cd(10); hXavg_Theta->Draw("colz");
}
#endif

194
Aux/SplitPolePlotter_MT.C Normal file
View File

@ -0,0 +1,194 @@
#include <TROOT.h>
#include "TTreeReader.h"
#include "TTreeReaderValue.h"
#include "TTreeReaderArray.h"
#include <ROOT/TTreeProcessorMP.hxx>
#include <ROOT/TTreeProcessorMT.hxx>
#include "ROOT/TProcessExecutor.hxx"
#include "ROOT/TThreadedObject.hxx"
#include "TH2F.h"
#include "TH1F.h"
#include "TCutG.h"
#include "TCanvas.h"
#include "SplitPolePlotter.C"
#include "../analyzers/SplitPoleHit.h"
void SplotPolePlotter_MT(TChain * chain, const int nThread, TCutG * pidCut = nullptr, double rhoOffset = 0, double rhoScaling = 1, bool isFSUDAQ = true){
//^====================== Thread Object, destoryed when merge
ROOT::TThreadedObject<TH2F> pCoin("hCoin", "Coincident ", 16, 0, 16, 16, 0, 16);
ROOT::TThreadedObject<TH1F> phMulti("hMulti", "Multiplicity", 16, 0, 16);
ROOT::TThreadedObject<TH2F> pPID("hPID", "PID; Scin_X ; AnodeB", 200, 0, 20000, 100, 0, isFSUDAQ ? 40000 : 5000);
ROOT::TThreadedObject<TH2F> phXavg_Q("hXavg_Q", "Xavg vs Q ", 200, XMIN, XMAX, 200, 0, isFSUDAQ ? 40000 : 5000);
ROOT::TThreadedObject<TH1F> phF("hF", "Front delay line position", 600, XMIN, XMAX);
ROOT::TThreadedObject<TH1F> phB("hB", "Back delay line position", 600, XMIN, XMAX);
ROOT::TThreadedObject<TH1F> phXavg("hAvg", "Xavg", 600, XMIN, XMAX);
ROOT::TThreadedObject<TH2F> phFocal("hFocal", "Front vs Back ", 200, XMIN, XMAX, 200, XMIN, XMAX);
ROOT::TThreadedObject<TH2F> phXavg_Theta("hXavg_Theta", "Xavg vs Theta ", 200, XMIN, XMAX, 200, 0.5, 1.4);
ROOT::TThreadedObject<TH2F> phRay("hRay", "Ray plot", 400, XMIN, XMAX, 400, -50, 50);
ROOT::TThreadedObject<TH1F> phEx("hEx", "Ex; Ex [MeV]; count/10 keV", 600, -1, 5);
ROOT::TThreadedObject<TH2F> phEx_Multi("hEx_Multi", "Ex vs Multi; Ex; Multi", 600, -1, 5, 16, 0, 16);
//^==================== TTreeProcessorMT
ROOT::EnableImplicitMT(nThread);
std::vector<std::string_view> fileList_view;
std::vector<std::string> fileList;
for( int k = 0; k < chain->GetNtrees(); k++){
fileList_view.push_back(chain->GetListOfFiles()->At(k)->GetTitle());
fileList.push_back(chain->GetListOfFiles()->At(k)->GetTitle());
}
ROOT::TTreeProcessorMT tp(fileList_view, "tree");
// tp.SetTasksPerWorkerHint(1);
std::mutex mutex;
int count = 0;
//^======================= Define process
auto ProcessTask = [&](TTreeReader &reader){
TTreeReaderValue<ULong64_t> evID = {reader, "evID"};
TTreeReaderValue<UInt_t> multi = {reader, "multi"};
TTreeReaderArray<UShort_t> sn = {reader, "sn"};
TTreeReaderArray<UShort_t> ch = {reader, "ch"};
TTreeReaderArray<UShort_t> e = {reader, "e"};
TTreeReaderArray<UShort_t> e2 = {reader, "e2"};
TTreeReaderArray<ULong64_t> e_t = {reader, "e_t"};
TTreeReaderArray<UShort_t> e_f = {reader, "e_f"};
mutex.lock();
count++;
printf("-------------- Thread_ID: %d \n", count);
mutex.unlock();
SplitPoleHit hit;
hit.SetMassTablePath("../analyzers/mass20.txt");
hit.CalConstants("12C", "d", "p", 16, 18); // 80MeV, 5 deg
hit.CalZoffset(0.750); // 1.41 T
while (reader.Next()) {
hit.ClearData();
phMulti->Fill(*multi);
// if( *multi != 9 ) continue;
for( int i = 0; i < *multi; i++){
// t2 = e_t[i];
// if( t2 < t1 ) printf("entry %lld-%d, timestamp is not in order. %llu, %llu\n", processedEntries, i, t2, t1);
if( i == 0 ) t1 = e_t[i];
// if( e[i] == 65535 ) continue;
if( ch[i] == ChMap::ScinR ) {hit.eSR = e[i]; hit.tSR = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::ScinL ) {hit.eSL = e[i]; hit.tSL = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::dFR ) {hit.eFR = e[i]; hit.tFR = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::dFL ) {hit.eFL = e[i]; hit.tFL = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::dBR ) {hit.eBR = e[i]; hit.tBR = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::dBL ) {hit.eBL = e[i]; hit.tBL = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::Cathode ) {hit.eCath = e[i]; hit.tCath = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::AnodeF ) {hit.eAF = e[i]; hit.tAF = e_t[i] + e_f[i]/1000;}
if( ch[i] == ChMap::AnodeB ) {hit.eAB = e[i]; hit.tAB = e_t[i] + e_f[i]/1000;}
for( int j = i+1; j < sn.GetSize(); j++){
pCoin->Fill(ch[i], ch[j]);
}
}
unsigned int dQ = hit.eAB; // delta Q
unsigned int Qt = hit.eSL; // total Q
if( Qt > 0 && dQ > 0 ) {
pPID->Fill(Qt, dQ);
}
//=============== PID gate cut
if( pidCut ){
if( !pidCut->IsInside(Qt, dQ) ) continue;
}
hit.CalData(2);
if( hit.theta > 1.2 || 0.5 > hit.theta ) continue;
if( (!TMath::IsNaN(hit.x1) || !TMath::IsNaN(hit.x2)) ) {
phFocal->Fill(hit.x1, hit.x2);
phF->Fill(hit.x1);
phB->Fill(hit.x2);
phXavg->Fill(hit.xAvg);
phXavg_Q->Fill(hit.xAvg, dQ);
phXavg_Theta->Fill( hit.xAvg, hit.theta);
for( int i = 0; i < 400; i++){
double z = -50 + 100/400.*i;
double x = (z/42.8625 + 0.5)* ( hit.x2-hit.x1) + hit.x1;
phRay->Fill(x,z);
}
double ex = hit.Rho2Ex( ((hit.xAvg - rhoOffset)/1000/rhoScaling + hit.GetRho0() ) );
//if( XMIN < hit.xAvg && hit.xAvg < XMAX) printf("x1 : %6.2f, x2 : %6.2f, xAvg %6.2f cm , ex : %f \n", hit.x1, hit.x2, hit.xAvg, ex);
phEx->Fill(ex);
phEx_Multi->Fill(ex, *multi);
}
}
return 0;
};
//^============================ Run TP
tp.Process(ProcessTask);
//^============================ Merge all ThreadedObject
auto coin = pCoin.Merge();
auto hMulti= phMulti.Merge();
auto hEx = phEx.Merge();
auto hEx_Multi = phEx_Multi.Merge();
auto PID = pPID.Merge();
auto hFocal = phFocal.Merge();
auto hF = phF.Merge();
auto hB = phB.Merge();
auto hXavg = phXavg.Merge();
auto hXavg_Q = phXavg_Q.Merge();
auto hXavg_Theta = phXavg_Theta.Merge();
auto hRay = phRay.Merge();
//^============================== Plot
gStyle->SetOptStat("neiou");
TCanvas * canvas = new TCanvas("cc", "Split-Pole", 2500, 1000);
canvas->Divide(5, 2);
canvas->cd(1); {
PID->DrawCopy("colz");
if( pidCut ) pidCut->Draw("same");
}
canvas->cd(2); hRay->DrawCopy("colz");
canvas->cd(3); hF->DrawCopy();
canvas->cd(4); hB->DrawCopy();
canvas->cd(5); hXavg_Q->DrawCopy("colz");
canvas->cd(6); hXavg->DrawCopy("colz");
canvas->cd(7); hEx->DrawCopy();
//canvas->cd(8); coin->DrawCopy("colz");
canvas->cd(8); hEx_Multi->DrawCopy("colz");
canvas->cd(9); canvas->cd(9)->SetLogy(); hMulti->DrawCopy();
canvas->cd(10); hXavg_Theta->DrawCopy("colz");
}

View File

@ -3,7 +3,7 @@
#include <algorithm>
#include <filesystem>
#define DEFAULT_HALFBUFFERSIZE 500000
#define DEFAULT_HALFBUFFERSIZE 5000000
class FSUReader{
@ -49,6 +49,7 @@ class FSUReader{
int GetNumCh() const{return numCh;}
int GetFileOrder() const{return order;}
int GetChMask() const{return chMask;}
int GetRunNum() const{return runNum;}
unsigned long GetFileByteSize() const {return inFileSize;}
void ClearHitList() { hit.clear();}
@ -63,7 +64,7 @@ class FSUReader{
void ClearTotalHitCount() {totalHitCount = 0;}
ulong GetTotalHitCount() const{return totalHitCount;}
std::vector<Hit> ReadBatch(unsigned int batchSize = 1000000, bool verbose = false); // output the sorted Hit
std::vector<Hit> ReadBatch(unsigned int batchSize = 1000000, bool traceOn = false, bool verbose = false); // output the sorted Hit
void PrintHit(ulong numHit = -1, ulong startIndex = 0) {
for( ulong i = startIndex; i < std::min(numHit, totalHitCount); i++){
@ -116,6 +117,7 @@ class FSUReader{
uShort order;
uShort chMask;
uShort numCh;
uShort runNum;
std::vector<unsigned int> blockPos;
std::vector<unsigned int > blockTimeStamp;
@ -262,14 +264,17 @@ inline void FSUReader::OpenFile(std::string fileName, uInt dataSize, int verbose
std::string token;
while (std::getline(iss, token, '_')) { tokens.push_back(token); }
sn = atoi(tokens[2].c_str());
tick2ns = atoi(tokens[4].c_str());
order = atoi(tokens[5].c_str());
short token_size = tokens.size();
// for( short i = 0; i < token_size; i ++ ) printf("%d | %s\n", i, tokens[i].c_str());
runNum = atoi(tokens[token_size-5].c_str());
sn = atoi(tokens[token_size-4].c_str());
tick2ns = atoi(tokens[token_size-2].c_str());
order = atoi(tokens[token_size-1].c_str());
DPPType = 0;
if( fileName.find("PHA") != std::string::npos ) DPPType = DPPTypeCode::DPP_PHA_CODE;
if( fileName.find("PSD") != std::string::npos ) DPPType = DPPTypeCode::DPP_PSD_CODE;
if( fileName.find("QDC") != std::string::npos ) DPPType = DPPTypeCode::DPP_QDC_CODE;
if( fileName.find("PHA") != std::string::npos ) { printf("Using PHA decode.\n"); DPPType = DPPTypeCode::DPP_PHA_CODE;}
if( fileName.find("PSD") != std::string::npos ) { printf("Using PSD decode.\n"); DPPType = DPPTypeCode::DPP_PSD_CODE;}
if( fileName.find("QDC") != std::string::npos ) { printf("Using QDC decode.\n"); DPPType = DPPTypeCode::DPP_QDC_CODE;}
if( DPPType == 0 ){
fclose(inFile);
inFile = nullptr;
@ -291,7 +296,7 @@ inline int FSUReader::ReadNextBlock(bool traceON, int verbose, uShort saveData){
if( inFile == NULL ) return -1;
if( feof(inFile) || filePos >= inFileSize) {
if( fileID >= 0 && fileID + 1 < (short) fileList.size() ){
printf("-------------- next file\n");
printf("-------------- next file | hit size : %zu\n", hit.size());
fileID ++;
OpenFile(fileList[fileID], data->GetDataSize(), 1 );
}else{
@ -365,12 +370,16 @@ inline int FSUReader::ReadNextBlock(bool traceON, int verbose, uShort saveData){
for( int i = start; i < start + data->NumEventsDecoded[ch]; i++ ){
int k = i % data->GetDataSize();
temp.sn = sn;
temp.ch = ch;
temp.energy = data->GetEnergy(ch, k);
temp.energy2 = data->GetEnergy2(ch, k);
temp.timestamp = data->GetTimestamp(ch, k);
// unsigned long long offset = 1000000;
// if( sn == 405 && ch == 0) temp.timestamp -= offset;
temp.fineTime = data->GetFineTime(ch, k);
temp.pileUp = data->GetPileUp(ch, k);
if( saveData > 1 ) {
@ -381,6 +390,8 @@ inline int FSUReader::ReadNextBlock(bool traceON, int verbose, uShort saveData){
if( temp.trace.size() > 0 ) temp.trace.clear();
}
// temp.Print();
hit.push_back(temp);
}
}
@ -491,7 +502,7 @@ inline void FSUReader::ScanNumBlock(int verbose, uShort saveData){
}
//^==============================================================
inline std::vector<Hit> FSUReader::ReadBatch(unsigned int batchSize, bool verbose){
inline std::vector<Hit> FSUReader::ReadBatch(unsigned int batchSize, bool traceOn, bool verbose){
// printf("%s sn:%d. filePos : %lu\n", __func__, sn, ftell(inFile));
@ -505,7 +516,7 @@ inline std::vector<Hit> FSUReader::ReadBatch(unsigned int batchSize, bool verbos
if( hit.size() == 0 ){
int res = 0;
do{
res = ReadNextBlock(true, 0, 3);
res = ReadNextBlock(traceOn, 0, 3);
}while ( hit.size() < batchSize && res == 0);
SortHit();
uLong t0_B = hit.at(0).timestamp;
@ -531,7 +542,7 @@ inline std::vector<Hit> FSUReader::ReadBatch(unsigned int batchSize, bool verbos
int res = 0;
do{
res = ReadNextBlock(true, 0, 3);
res = ReadNextBlock(traceOn, 0, 3);
}while ( hit.size() < batchSize && res == 0);
SortHit();
uLong t0_B = hit.at(0).timestamp;

View File

@ -81,7 +81,7 @@ int main(int argc, char **argv) {
tempInfo.fileName = inFileName[i];
tempInfo.readerID = i;
tempInfo.SN = reader[i]->GetSN();
tempInfo.hitCount = reader[i]->GetHitCount();
tempInfo.hitCount = reader[i]->GetTotalHitCount();
tempInfo.fileSize = reader[i]->GetFileByteSize();
tempInfo.tick2ns = reader[i]->GetTick2ns();
tempInfo.DPPType = reader[i]->GetDPPType();
@ -208,7 +208,7 @@ int main(int argc, char **argv) {
}else{
group[gpID].hitID = 0;
uShort rID = group[gpID].readerIDList[group[gpID].currentID];
group[gpID].hitCount = reader[rID]->GetHitCount();
group[gpID].hitCount = reader[rID]->GetTotalHitCount();
printf("-----> go to the next file, %s \n", fileInfo[rID].fileName.c_str() );
}
}

View File

@ -110,7 +110,7 @@ int main(int argc, char **argv) {
tempInfo.fileName = outFileName;
tempInfo.readerID = i;
tempInfo.SN = reader[i]->GetSN();
tempInfo.hitCount = reader[i]->GetHitCount();
tempInfo.hitCount = reader[i]->GetTotalHitCount();
tempInfo.fileSize = reader[i]->GetTSFileSize();
tempInfo.tick2ns = reader[i]->GetTick2ns();
tempInfo.DPPType = reader[i]->GetDPPType();

View File

@ -1,90 +1,114 @@
#include "fsuReader.h"
#include "../MultiBuilder.cpp"
// #include "../MultiBuilder.cpp"
#include "SplitPolePlotter.C"
#include "SplitPolePlotter_MT.C"
void script(){
FSUReader * reader = new FSUReader("~/ExpData/testing/.fsu", 16);
Data * data = reader->GetData();
data->tick2ns = 4;
TChain * chain = new TChain("tree");
// chain->Add("raw_binary/run_13/run013_3000.root");
// chain->Add("data/run*_3000.root");
chain->Add("data/12C_dp_*_3000.root");
reader->ScanNumBlock();
// TFile * pidCutFile = new TFile("cut_proton.root");
TFile * pidCutFile = new TFile("cut_proton_FSU.root");
TCutG * pidCut = (TCutG *) pidCutFile->Get("protons");
// SplitPolePlotter(chain, pidCut, 123.307, 2.75, false); // for CoMPASS data
// SplitPolePlotter(chain, pidCut, 123.307, 2.75, true); // faster then MT?
// for( int i = 0; i < 500 ; i++ ) reader->ReadNextBlock(0, 0);
// int ch = 5;
// std::vector<unsigned long long > tList;
// int nEvent = 0;
// for( int i = 0; i < data->TotNumNonPileUpEvents[ch]; i++){
// tList.push_back(data->Timestamp[ch][i]);
// printf("%3d | %d %llu \n", i, data->Energy[ch][i], data->Timestamp[ch][i]);
// nEvent ++;
// }
// std::sort(tList.begin(), tList.end());
// unsigned long long dTime = tList.back() - tList.front();
// double sec = dTime * data->tick2ns / 1e9;
// printf("=========== %llu, %llu = %llu | %f sec | %f Hz\n", tList.back(), tList.front(), dTime, sec, nEvent/sec );
//data->PrintStat(0);
SplotPolePlotter_MT(chain, 5, pidCut, 123.307, 2.75, true);
data->ClearData();
data->ClearTriggerRate();
//^=====================================================
// FSUReader * reader = new FSUReader("data/12C_dp_002_19555_PSD_4_000.fsu", 10000, 2);
// reader->ScanNumBlock(1, 0);
// reader->ReadNextBlock(0, 9);
// for( int i = 0; i < 10 ; i++ ) reader->ReadNextBlock(0, 9);
// std::vector<Hit> hitList = reader->ReadBatch(10, true);
// for ( int i = 0; i < 10 ; i ++) hitList[i].Print();
// // int ch = 5;
// // std::vector<unsigned long long > tList;
// // int nEvent = 0;
// // for( int i = 0; i < data->TotNumNonPileUpEvents[ch]; i++){
// // tList.push_back(data->Timestamp[ch][i]);
// // printf("%3d | %d %llu \n", i, data->Energy[ch][i], data->Timestamp[ch][i]);
// // nEvent ++;
// // }
// // std::sort(tList.begin(), tList.end());
// // unsigned long long dTime = tList.back() - tList.front();
// // double sec = dTime * data->tick2ns / 1e9;
// // printf("=========== %llu, %llu = %llu | %f sec | %f Hz\n", tList.back(), tList.front(), dTime, sec, nEvent/sec );
// //data->PrintStat(0);
MultiBuilder * mb = new MultiBuilder(data, reader->GetDPPType(), 334);
mb->SetTimeWindow(10000);
unsigned long totNumBlock = reader->GetTotNumBlock();
int lastDataIndex = 0;
int lastLoopIndex = 0;
for( unsigned long i = 0; i < 2; i++){
reader->ReadNextBlock();
// int maxDataIndex = 0;
// int maxLoopIndex = 0;
// for( int ch = 0; ch < 16 ; ch++){
// if( data->DataIndex[ch] > maxDataIndex ) maxDataIndex = data->DataIndex[ch];
// if( data->LoopIndex[ch] > maxLoopIndex ) maxLoopIndex = data->LoopIndex[ch];
// }
// if( (maxLoopIndex * MaxNData + maxDataIndex) - (lastLoopIndex * MaxNData + lastDataIndex) > MaxNData * 0.05){
// printf("Agg ID : %lu \n", i );
// data->PrintStat();
// data->PrintAllData();
// mb->BuildEvents();
// mb->PrintAllEvent();
// mb->PrintStat();
// lastDataIndex = maxDataIndex;
// lastLoopIndex = maxLoopIndex;
// }
}
// data->ClearData();
// data->ClearTriggerRate();
data->PrintStat();
data->PrintAllData();
//mb->BuildEvents(true);
// MultiBuilder * mb = new MultiBuilder(data, reader->GetDPPType(), 334);
// mb->SetTimeWindow(10000);
// unsigned long totNumBlock = reader->GetTotNumBlock();
// int lastDataIndex = 0;
// int lastLoopIndex = 0;
mb->BuildEventsBackWard(300);
// for( unsigned long i = 0; i < 2; i++){
mb->PrintAllEvent();
mb->PrintStat();
// reader->ReadNextBlock();
// // int maxDataIndex = 0;
// // int maxLoopIndex = 0;
// // for( int ch = 0; ch < 16 ; ch++){
// // if( data->DataIndex[ch] > maxDataIndex ) maxDataIndex = data->DataIndex[ch];
// // if( data->LoopIndex[ch] > maxLoopIndex ) maxLoopIndex = data->LoopIndex[ch];
// // }
// // if( (maxLoopIndex * MaxNData + maxDataIndex) - (lastLoopIndex * MaxNData + lastDataIndex) > MaxNData * 0.05){
// // printf("Agg ID : %lu \n", i );
// // data->PrintStat();
// // data->PrintAllData();
// // mb->BuildEvents();
// // mb->PrintAllEvent();
// // mb->PrintStat();
// // lastDataIndex = maxDataIndex;
// // lastLoopIndex = maxLoopIndex;
// // }
// }
delete mb;
delete reader;
// data->PrintStat();
// data->PrintAllData();
// //mb->BuildEvents(true);
}
// mb->BuildEventsBackWard(300);
// mb->PrintAllEvent();
// mb->PrintStat();
// delete mb;
// delete reader;
}

View File

@ -321,82 +321,82 @@ int TestDigitizerRaw(){
}
void Compare_CAEN_Decoder(){
std::unique_ptr<Digitizer> digi = std::make_unique<Digitizer>(0, 49093, false, true);
Data * data = digi->GetData();
int ret;
int handle = digi->GetHandle();
CAEN_DGTZ_DPP_PSD_Event_t *Events[16]; /// events buffer
uint32_t NumEvents[16];
uint32_t AllocatedSize = 0;
ret |= CAEN_DGTZ_MallocDPPEvents(handle, reinterpret_cast<void**>(&Events), &AllocatedSize) ;
printf("allowcated %d byte for Events\n", AllocatedSize);
printf("======================== start ACQ \n");
digi->StartACQ();
int ch = 0;
for( int i = 0; i < 5; i ++ ){
usleep(1000*1000); // every 1 second
digi->ReadData();
// data->CopyBuffer(cpBuffer, bufferSize);
data->DecodeBuffer(false, 4);
if( data->nByte > 0 ){
ret = (CAEN_DGTZ_ErrorCode) CAEN_DGTZ_GetDPPEvents(handle, data->buffer, data->nByte, reinterpret_cast<void**>(&Events), NumEvents);
if (ret) {
printf("Error when getting events from data %d\n", ret);
continue;
}
printf("============ %u\n", NumEvents[0]);
for( int ev = 0; ev < NumEvents[0]; ev++ ){
printf("-------- ev %d\n", ev);
printf( " Format : 0x%04x\n", Events[ch][ev].Format);
printf( "TimeTag : 0x%08x\n", Events[ch][ev].TimeTag);
printf(" E_short : 0x%04x\n", Events[ch][ev].ChargeShort);
printf(" E_long : 0x%04x\n", (Events[ch][ev].ChargeLong & 0xffff));
printf("Baseline : 0x%04x\n", (Events[ch][ev].Baseline & 0xffff));
printf(" Pur : 0x%04x\n", Events[ch][ev].Pur);
printf(" Extra : 0x%08x\n", Events[ch][ev].Extras);
}
}
}
digi->StopACQ();
printf("======================== ACQ Stopped.\n");
}
//^======================================
int main(int argc, char* argv[]){
TestDigitizerRaw();
// CheckBufferSize(5, 4);
Compare_CAEN_Decoder();
//GetOneAgg();
// Data * data = digi->GetData();
// MultiBuilder * builder = new MultiBuilder(data, DPPType::DPP_PHA_CODE, digi->GetSerialNumber());
// builder->SetTimeWindow(100);
// digi->WriteRegister(DPP::QDC::PreTrigger, 60, -1);
// digi->WriteRegister(DPP::QDC::TriggerThreshold_sub2, 17, -1);
// digi->SetBits(DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::ChargeSensitivity, 0, -1);
// digi->SetBits(DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::InputSmoothingFactor, 4, -1);
// digi->SetBits(DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::BaselineAvg, 2, -1);
// digi->WriteRegister(DPP::QDC::GateWidth, 608/16, -1);
// digi->WriteRegister(DPP::QDC::GroupEnableMask, 0x01);
// digi->WriteRegister(DPP::QDC::NumberEventsPerAggregate, 10, -1);
// digi->WriteRegister(DPP::AggregateOrganization, 0, -1);
// digi->WriteRegister(DPP::MaxAggregatePerBlockTransfer, 100, -1);
// digi->SetBits(DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::Polarity, 0, -1);
/*
digi->SetBits(DPP::BoardConfiguration, DPP::Bit_BoardConfig::EnableExtra2, 1, -1);
digi->SetBits(DPP::BoardConfiguration, DPP::Bit_BoardConfig::RecordTrace, 0, -1);
Data * data = digi->GetData();
MultiBuilder * builder = new MultiBuilder(data, DPPType::DPP_PHA_CODE, digi->GetSerialNumber());
builder->SetTimeWindow(100);
//remove("haha_*.fsu");
//data->OpenSaveFile("haha");
digi->StartACQ();
for( int i = 0; i < 5; i ++ ){
usleep(1000*1000);
digi->ReadData();
data->DecodeBuffer(true, 0);
//data->DecodeBuffer(false, 2);
//data->SaveData();
//data->PrintStat();
data->PrintAllData(true);
//builder->BuildEvents(false, true, true);
builder->BuildEventsBackWard(20, true);
builder->PrintStat();
// int index = data->NumEventsDecoded[0];
// printf("-------------- %ld \n", data->Waveform1[0][index].size());
}
digi->StopACQ();
//data->CloseSaveFile();
builder->BuildEvents(true, true, true);
data->PrintAllData();
builder->PrintAllEvent(); // TODO
*/
// digi->CloseDigitizer();
// delete digi;
return 0;
}
//*********************************
//*********************************

View File

@ -90,6 +90,7 @@ class Data{
unsigned short GetNChannel() const {return numInputCh;}
void PrintBuffer();
void CopyBuffer( const char * buffer, const unsigned int size);
void DecodeBuffer(bool fastDecode, int verbose = 0); /// fastDecode will not save waveform
@ -310,7 +311,7 @@ inline void Data::ClearData(){
if( ch >= numInputCh) break;
for( int j = 0; j < dataSize; j++){
Timestamp[ch][j] = 0;
fineTime[ch][j] = 0;
fineTime[ch][j] = -1;
Energy[ch][j] = 0;
Energy2[ch][j] = 0;
Waveform1[ch][j].clear();
@ -330,6 +331,8 @@ inline void Data::ClearData(){
tempDigiWaveform3.clear();
tempDigiWaveform4.clear();
outFileIndex = 0;
ClearNumEventsDecoded();
ClearTriggerRate();
@ -344,7 +347,10 @@ inline void Data::ClearBuffer(){
}
inline void Data::CopyBuffer(const char * buffer, const unsigned int size){
if( this->buffer ) delete this->buffer;
this->buffer = (char*) malloc(size);
std::memcpy(this->buffer, buffer, size);
this->nByte = size;
}
inline void Data::ClearReferenceTime(){
@ -557,12 +563,21 @@ inline void Data::PrintChData(unsigned short ch, unsigned int maxRowDisplay) con
//^#######################################################
//^####################################################### Decode
inline void Data::PrintBuffer(){
if( buffer == NULL || nByte == 0 ) return;
printf("============== Received nByte : %u\n", nByte);
for( unsigned int i = 0; i < nByte/4; i++ ) {
ReadBuffer(i, 2);
printf("\n");
}
}
inline unsigned int Data::ReadBuffer(unsigned int nWord, int verbose){
if( buffer == NULL ) return 0;
unsigned int word = 0;
for( int i = 0 ; i < 4 ; i++) word += ((buffer[i + 4 * nWord] & 0xFF) << 8*i);
if( verbose >= 2) printf("%6d | 0x%08X | ", nWord, word);
if( verbose >= 2) printf("%6d | 0x%08X |", nWord, word);
return word;
}
@ -882,7 +897,11 @@ inline int Data::DecodePHADualChannelBlock(unsigned int ChannelMask, bool fastDe
Energy[channel][DataIndex[channel]] = energy;
Timestamp[channel][DataIndex[channel]] = timeStamp * tick2ns;
if(extra2Option == 2 ) fineTime[channel][DataIndex[channel]] = (extra2 & 0x03FF );
if(extra2Option == 2 ) {
fineTime[channel][DataIndex[channel]] = (extra2 & 0x03FF ) * tick2ns; // in ps, the tick2ns is a conversion factor
}else{
fineTime[channel][DataIndex[channel]] = -1;
}
PileUp[channel][DataIndex[channel]] = pileUp;
NumEventsDecoded[channel] ++;
@ -1085,7 +1104,11 @@ inline int Data::DecodePSDDualChannelBlock(unsigned int ChannelMask, bool fastDe
Energy2[channel][DataIndex[channel]] = Qshort;
Energy[channel][DataIndex[channel]] = Qlong;
Timestamp[channel][DataIndex[channel]] = timeStamp * tick2ns;
if( extraOption == 2 ) fineTime[channel][DataIndex[channel]] = extra & 0x3FF;
if( extraOption == 2 ) {
fineTime[channel][DataIndex[channel]] = (extra & 0x3FF) * tick2ns; //in ps, tick2ns is justa conversion factor
}else{
fineTime[channel][DataIndex[channel]] = -1; //in ps, tick2ns is justa conversion factor
}
NumEventsDecoded[channel] ++;
if( !pileup){
@ -1110,10 +1133,16 @@ inline int Data::DecodePSDDualChannelBlock(unsigned int ChannelMask, bool fastDe
//if( DataIndex[channel] >= dataSize ) ClearData();
//if( verbose >= 2 ) printf("extra : 0x%08x, Qshort : %d, Qlong : %d \n", extra, Qshort, Qlong);
if( verbose == 1 ) printf("ch : %2d, Qshort : %6d, Qlong : %6d, timestamp : %llu\n",
channel, Qshort, Qlong, timeStamp * tick2ns);
if( verbose >= 2 ) printf("Qshort : %6d, Qlong : %6d, timestamp : %llu\n",
Qshort, Qlong, timeStamp * tick2ns);
if( verbose >= 1 ) {
if( extraOption == 0){
printf("Qshort : %6d, Qlong : %6d, timestamp : %llu, baseline : %u\n",
Qshort, Qlong, timeStamp * tick2ns, (extra & 0xFFFF) * 4);
}
if( extraOption == 2){
printf("Qshort : %6d, Qlong : %6d, timestamp : %llu, fineTime : %u\n",
Qshort, Qlong, timeStamp * tick2ns, (extra & 0x3FF) * tick2ns);
}
}

View File

@ -183,7 +183,6 @@ int Digitizer::OpenDigitizer(int boardID, int portID, bool program, bool verbose
/// change address 0xEF08 (5 bits), this will reflected in the 2nd word of the Board Agg. header.
ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardID, (DPPType & 0xF));
//TODO somehow the bdInfo does not work, use DPPType to set it
uint32_t bdInfo = GetSettingFromMemory(DPP::BoardInfo_R);
uint32_t haha = ((bdInfo >> 8 ) & 0xFF);
@ -258,6 +257,7 @@ int Digitizer::OpenDigitizer(int boardID, int portID, bool program, bool verbose
ErrorMsg("end of OpenDigitizer");
softwareDisable = false;
AcqRun = false;
if( isConnected ) isDummy = false;
@ -278,16 +278,18 @@ int Digitizer::CloseDigitizer(){
isConnected = false;
ret = CAEN_DGTZ_SWStopAcquisition(handle);
printf("-------- Closing Digtizer Board : %d Port : %d \n", boardID, portID);
printf(" Model %s with handle %d using %s\n", BoardInfo.ModelName, handle, LinkType == CAEN_DGTZ_USB ? "USB" : "Optical Link");
if( LinkType == CAEN_DGTZ_USB ) printf(" Model %s with handle %d using USB\n", BoardInfo.ModelName, handle);
if( LinkType == CAEN_DGTZ_OpticalLink ) printf(" Model %s with handle %d using Optical Fiber\n", BoardInfo.ModelName, handle);
if( LinkType == CAEN_DGTZ_USB_A4818 ) printf(" Model %s with handle %d using A4818\n", BoardInfo.ModelName, handle);
ret |= CAEN_DGTZ_CloseDigitizer(handle);
return ret;
}
void Digitizer::SetRegChannelMask(uint32_t mask){
DebugPrint("%s", "Digitizer");
if( softwareDisable ) return;
if( AcqRun ) return;
if( !isConnected ) return;
regChannelMask = mask;
ret |= CAEN_DGTZ_SetChannelEnableMask(handle, regChannelMask);
@ -309,6 +311,7 @@ bool Digitizer::GetInputChannelOnOff(unsigned ch) {
void Digitizer::SetRegChannelOnOff(unsigned short ch, bool onOff){
DebugPrint("%s", "Digitizer");
if( softwareDisable ) return;
if( AcqRun ) return;
if( !isConnected ) return;
regChannelMask = ((regChannelMask & ~( 1 << ch) ) | ( onOff << ch)) ;
SetRegChannelMask(regChannelMask);
@ -316,6 +319,8 @@ void Digitizer::SetRegChannelOnOff(unsigned short ch, bool onOff){
void Digitizer::ProgramBoard(){
DebugPrint("%s", "Digitizer");
if( softwareDisable ) return;
if( AcqRun ) return;
if( DPPType == DPPTypeCode::DPP_PHA_CODE ) ProgramBoard_PHA();
if( DPPType == DPPTypeCode::DPP_PSD_CODE ) ProgramBoard_PSD();
if( DPPType == DPPTypeCode::DPP_QDC_CODE ) ProgramBoard_QDC();
@ -323,7 +328,6 @@ void Digitizer::ProgramBoard(){
int Digitizer::ProgramBoard_PHA(){
DebugPrint("%s", "Digitizer");
if( softwareDisable ) return 0;
printf("===== Digitizer::%s\n", __func__);
@ -402,8 +406,6 @@ int Digitizer::ProgramBoard_PHA(){
}
int Digitizer::ProgramBoard_PSD(){
if( softwareDisable ) return 0;
printf("===== Digitizer::%s\n", __func__);
//ret = CAEN_DGTZ_Reset(handle);
@ -437,6 +439,12 @@ int Digitizer::ProgramBoard_PSD(){
ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xF, 0xAAAA);
}
ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::PSD::DPPAlgorithmControl2_G) + 0x7000 , 0x00000200 ); // use fine time
ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::DPPAlgorithmControl) + 0x7000 , 0x00100000 ); // baseline 16 sample
ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::PSD::TriggerThreshold) + 0x7000 , 100 );
ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::PreTrigger) + 0x7000 , 20 );
ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::RecordLength_G) + 0x7000 , 80 );
@ -461,8 +469,6 @@ int Digitizer::ProgramBoard_PSD(){
}
int Digitizer::ProgramBoard_QDC(){
if( softwareDisable ) return 0;
printf("===== Digitizer::%s\n", __func__);
Reset();
@ -568,14 +574,13 @@ void Digitizer::StartACQ(){
}
AcqRun = true;
data->ClearTriggerRate();
data->ClearData();
if( DPPType == DPPTypeCode::DPP_QDC_CODE ) SetOptimialAggOrg();
printf(" ACQ mode : %s (%d), TRG-OUT mode : %s (%d) \n", acqStr.c_str(), acqID, trgOutStr.c_str(), trgOutID);
AcqRun = true;
usleep(1000); // wait for 1 msec to start/Arm ACQ;
ret = CAEN_DGTZ_SWStartAcquisition(handle);
@ -603,6 +608,8 @@ void Digitizer::StopACQ(){
data->ClearBuffer();
data->ClearReferenceTime();
data->ZeroTotalFileSize();
ReadACQStatus();
}
unsigned int Digitizer::CalByteForBuffer(bool verbose){
@ -667,7 +674,7 @@ unsigned int Digitizer::CalByteForBufferCAEN(){
uint32_t AllocatedSize;
ret = CAEN_DGTZ_MallocReadoutBuffer(handle, &BufferCAEN, &AllocatedSize);
delete BufferCAEN;
if( BufferCAEN) delete BufferCAEN;
return AllocatedSize;
}
@ -723,6 +730,7 @@ void Digitizer::ReadAndPrintACQStatue(){
//===========================================================
void Digitizer::WriteRegister (Reg registerAddress, uint32_t value, int ch, bool isSave2MemAndFile){
if( softwareDisable ) return;
if( AcqRun ) return;
printf("WRITE|%30s[0x%04X](digi-%d,ch-%02d) [0x%04X]: 0x%08X \n", registerAddress.GetNameChar(), registerAddress.GetAddress(),GetSerialNumber(), ch, registerAddress.ActualAddress(ch), value);
if( !isConnected ) {
@ -769,6 +777,7 @@ void Digitizer::WriteRegister (Reg registerAddress, uint32_t value, int ch, bool
uint32_t Digitizer::ReadRegister(Reg registerAddress, unsigned short ch, bool isSave2MemAndFile, std::string str ){
DebugPrint("%s", "Digitizer");
if( softwareDisable ) return 0;
if( AcqRun ) return 0;
if( !isConnected ) return 0;
if( registerAddress.GetRWType() == RW::WriteONLY ) return 0;
// if( registerAddress == DPP::QDC::RecordLength_W ) return 0;
@ -857,8 +866,8 @@ Reg Digitizer::FindRegister(uint32_t address){
void Digitizer::ReadAllSettingsFromBoard(bool force){
if( softwareDisable ) return;
if( !isConnected ) return;
if( AcqRun ) return;
if( !isConnected ) return;
if( isSettingFilledinMemeory && !force) return;
printf("===== Digitizer(%d)::%s \n", GetSerialNumber(), __func__);
@ -917,6 +926,7 @@ void Digitizer::ReadAllSettingsFromBoard(bool force){
void Digitizer::ProgramSettingsToBoard(){
DebugPrint("%s", "Digitizer");
if( softwareDisable ) return;
if( AcqRun ) return;
if( !isConnected || isDummy ) return;
printf("========== %s \n", __func__);
@ -1005,6 +1015,7 @@ void Digitizer::ProgramSettingsToBoard(){
}
void Digitizer::SetSettingToMemory(Reg registerAddress, unsigned int value, unsigned short ch ){
if( AcqRun ) return;
DebugPrint("%s", "Digitizer");
unsigned short index = registerAddress.Index(ch);
if( index > SETTINGSIZE ) return;
@ -1300,6 +1311,7 @@ void Digitizer::ErrorMsg(std::string header){
void Digitizer::SetDPPAlgorithmControl(uint32_t bit, int ch){
DebugPrint("%s", "Digitizer");
if( softwareDisable ) return;
if( AcqRun ) return;
WriteRegister( DPP::DPPAlgorithmControl, bit, ch);
if( ret != 0 ) ErrorMsg(__func__);
}
@ -1307,6 +1319,7 @@ void Digitizer::SetDPPAlgorithmControl(uint32_t bit, int ch){
unsigned int Digitizer::ReadBits(Reg address, unsigned int bitLength, unsigned int bitSmallestPos, int ch ){
DebugPrint("%s", "Digitizer");
if( softwareDisable ) return 0;
if( AcqRun ) return 0;
int tempCh = ch;
if (ch < 0 && address < 0x8000 ) tempCh = 0; /// take ch-0
uint32_t bit = ReadRegister(address, tempCh);
@ -1317,6 +1330,7 @@ unsigned int Digitizer::ReadBits(Reg address, unsigned int bitLength, unsigned i
void Digitizer::SetBits(Reg address, unsigned int bitValue, unsigned int bitLength, unsigned int bitSmallestPos, int ch){
DebugPrint("%s", "Digitizer");
if( softwareDisable ) return;
if( AcqRun ) return;
///printf("address : 0x%X, value : 0x%X, len : %d, pos : %d, ch : %d \n", address, bitValue, bitLength, bitSmallestPos, ch);
uint32_t bit ;
uint32_t bitmask = (uint(pow(2, bitLength)-1) << bitSmallestPos);
@ -1361,7 +1375,6 @@ void Digitizer::SetOptimialAggOrg(){
printf(" Record Length (bit) : %u = %u sample = %u ns\n", RecordLen, RecordLen*8, RecordLen*8*16);
printf("==============================================================\n");
int eventSize = 6 + 2 * Ex + traceOn * RecordLen * 8; // sample
printf(" estimated event size : %d sample \n", eventSize);
double maxAggOrg = log2( MemorySizekSample * 1024 / eventSize / EventAgg );

View File

@ -206,6 +206,10 @@ class Digitizer{
return returnData;
}
void SetTrace(bool onOff){
SetBits(DPP::BoardConfiguration, DPP::Bit_BoardConfig::RecordTrace, onOff, -1);
}
};

View File

@ -69,7 +69,6 @@ public:
digi->WriteRegister(DPP::SoftwareClear_W, 1);
digi->GetData()->ClearData();
}
digi->ReadACQStatus();
digiMTX[ID].unlock();
emit sendMsg("Digi-" + QString::number(digi->GetSerialNumber()) + " ACQ off.");
stop = true;
@ -119,6 +118,7 @@ public:
waitTime = 20; // multiple of 100 mili sec
stop = false;
}
bool isStopped() const {return stop;}
void Stop() { this->stop = true;}
void SetWaitTimeinSec(float sec) {waitTime = sec * 10 ;}
float GetWaitTimeinSec() const {return waitTime/10.;}

View File

@ -7,6 +7,8 @@
#include <QDir>
#include <QFileDialog>
#include <QSortFilterProxyModel>
#include <QApplication>
#include <QScreen>
#define ComBoxMixed "Mixed"
// bit = 0, bit = 1
@ -38,7 +40,16 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr
enableSignalSlot = false;
setWindowTitle("Digitizer Settings");
setGeometry(0, 0, 1700, 850);
//====== resize window if screen too small
QScreen * screen = QGuiApplication::primaryScreen();
QRect screenGeo = screen->geometry();
if( screenGeo.width() < 1700 || screenGeo.height() < 850) {
setGeometry(0, 0, screenGeo.width() - 100, screenGeo.height() - 100);
}else{
setGeometry(0, 0, 1700, 850);
}
// setGeometry(0, 0, 1700, 850);
tabWidget = new QTabWidget(this);
setCentralWidget(tabWidget);
@ -185,9 +196,9 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr
{//^======================= Buttons
QWidget * buttonsWidget = new QWidget(tab);
tabLayout_V1->addWidget(buttonsWidget);
QGridLayout * buttonLayout = new QGridLayout(buttonsWidget);
buttonsWidget[iDigi] = new QWidget(tab);
tabLayout_V1->addWidget(buttonsWidget[iDigi]);
QGridLayout * buttonLayout = new QGridLayout(buttonsWidget[iDigi]);
buttonLayout->setSpacing(2);
int rowID = 0 ;
@ -258,7 +269,7 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr
// connect(bnSaveSettingsToText, &QPushButton::clicked, this, [=](){ SaveSetting(1);});
//checkBox, to coupled or decouple the setting file.
chkCoupledSettingFile = new QCheckBox("Update Setting", this);
chkCoupledSettingFile = new QCheckBox("Live Setting Update", this);
buttonLayout->addWidget(chkCoupledSettingFile, rowID, 2);
chkCoupledSettingFile->setCheckState(Qt::CheckState::Unchecked);
connect(chkCoupledSettingFile, &QCheckBox::stateChanged, this, [=](int state){
@ -358,7 +369,8 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr
//If any digitizer is running ACQ, disable the panel.
for( unsigned int iDigi = 0; iDigi < nDigi; iDigi ++){
if( digi[iDigi]->IsRunning() ) {
this->setEnabled(false);
// this->setEnabled(false);
EnableButtons(false);
break;
}
}
@ -1366,6 +1378,7 @@ void DigiSettingsPanel::SetUpChannelMask(unsigned int digiID){
connect(bnChEnableMask[digiID][i], &QPushButton::clicked, this, [=](){
if( !enableSignalSlot) return;
if( digi[digiID]->IsRunning() ) return;
if( bnChEnableMask[digiID][i]->styleSheet() == "" ){
bnChEnableMask[digiID][i]->setStyleSheet("background-color : green;");
@ -2486,7 +2499,7 @@ void DigiSettingsPanel::SetUpChannel_PSD(){
QLabel * lb4 = new QLabel("Veto Width", this); lb4->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb4, 0, 6);
QLabel * lb5 = new QLabel("Veto Step", this); lb5->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb5, 0, 8);
}
SetUpComboBoxBit(cbVetoSource[ID][ch], "", tabLayout, ch + 1, 1, DPP::PHA::Bit_DPPAlgorithmControl2::ListVetoSource, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::VetoSource, 1, ch);
SetUpComboBoxBit(cbVetoSource[ID][ch], "", tabLayout, ch + 1, 1, DPP::PSD::Bit_DPPAlgorithmControl2::ListVetoSource, DPP::PSD::DPPAlgorithmControl2_G, DPP::PSD::Bit_DPPAlgorithmControl2::VetoSource, 1, ch);
SetUpComboBoxBit(cbVetoMode[ID][ch], "", tabLayout, ch + 1, 3, DPP::PSD::Bit_DPPAlgorithmControl2::ListVetoMode, DPP::PSD::DPPAlgorithmControl2_G, DPP::PSD::Bit_DPPAlgorithmControl2::VetoMode, 1, ch);
SetUpSpinBox(sbVetoWidth[ID][ch], "", tabLayout, ch + 1, 5, DPP::VetoWidth, ch);
SetUpComboBoxBit(cbVetoStep[ID][ch], "", tabLayout, ch + 1, 7, DPP::Bit_VetoWidth::ListVetoStep, DPP::VetoWidth, DPP::Bit_VetoWidth::VetoStep, 1, ch);
@ -2497,8 +2510,8 @@ void DigiSettingsPanel::SetUpChannel_PSD(){
QLabel * lb2 = new QLabel("Extra Option [G]", this); lb2->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb2, 0, 2);
QLabel * lb3 = new QLabel("TRG-OUT Ch. Prb. [G]", this); lb3->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb3, 0, 4);
}
SetUpComboBoxBit(cbExtra2Option[ID][ch], "", tabLayout, ch + 1, 1, DPP::PHA::Bit_DPPAlgorithmControl2::ListExtra2, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::Extra2Option, 2, ch);
SetUpComboBoxBit(cbTRGOUTChannelProbe[ID][ch], "", tabLayout, ch + 1, 3, DPP::PSD::Bit_DPPAlgorithmControl2::ListChannelProbe, DPP::PSD::DPPAlgorithmControl2_G, DPP::PSD::Bit_DPPAlgorithmControl2::ChannelProbe, 2, ch);
SetUpComboBoxBit(cbExtra2Option[ID][ch], "", tabLayout, ch + 1, 1, DPP::PSD::Bit_DPPAlgorithmControl2::ListExtraWordOpt, DPP::PSD::DPPAlgorithmControl2_G, DPP::PSD::Bit_DPPAlgorithmControl2::ExtraWordOption, 1, ch);
SetUpComboBoxBit(cbTRGOUTChannelProbe[ID][ch], "", tabLayout, ch + 1, 3, DPP::PSD::Bit_DPPAlgorithmControl2::ListChannelProbe, DPP::PSD::DPPAlgorithmControl2_G, DPP::PSD::Bit_DPPAlgorithmControl2::ChannelProbe, 1, ch);
}
}
@ -3620,6 +3633,20 @@ void DigiSettingsPanel::SyncCheckBox(QCheckBox *(&chk)[][MaxRegChannel+1]){
}
}
void DigiSettingsPanel::EnableButtons(bool enable){
for( int i = 0; i < nDigi; i++ ){
if( !enable ) {
leSaveFilePath[i]->setText("changing setting is disabled due to ACQ is running.");
leSaveFilePath[i]->setStyleSheet("color:red;");
}else{
leSaveFilePath[i]->setText((QString::fromStdString(digi[i]->GetSettingFileName())));
leSaveFilePath[i]->setStyleSheet("");
}
buttonsWidget[i]->setEnabled(enable);
}
}
void DigiSettingsPanel::SyncAllChannelsTab_PHA(){
DebugPrint("%s", "DigiSettingsPanel");
SyncSpinBox(sbRecordLength);
@ -3836,16 +3863,16 @@ void DigiSettingsPanel::UpdateSettings_PSD(){
chkRejOverRange[ID][ch]->setChecked( Digitizer::ExtractBits(dpp, DPP::Bit_DPPAlgorithmControl_PSD::RejectOverRange));
chkTestPule[ID][ch]->setChecked( Digitizer::ExtractBits(dpp, DPP::Bit_DPPAlgorithmControl_PSD::InternalTestPulse));
chkDisableOppositePulse[ID][ch]->setChecked( Digitizer::ExtractBits(dpp, DPP::Bit_DPPAlgorithmControl_PSD::DisableOppositePolarityInhibitZeroCrossingOnCFD));
chkDisableSelfTrigger[ID][ch]->setChecked( Digitizer::ExtractBits(dpp, DPP::Bit_DPPAlgorithmControl_PSD::DisableSelfTrigger));
chkRejPileUp[ID][ch]->setChecked( Digitizer::ExtractBits(dpp, DPP::Bit_DPPAlgorithmControl_PSD::RejectPileup));
chkPileUpInGate[ID][ch]->setChecked( Digitizer::ExtractBits(dpp, DPP::Bit_DPPAlgorithmControl_PSD::PileupWithinGate));
chkDisableTriggerHysteresis[ID][ch]->setChecked( Digitizer::ExtractBits(dpp, DPP::Bit_DPPAlgorithmControl_PSD::DisableTriggerHysteresis));
uint32_t dpp2 = digi[ID]->GetSettingFromMemory(DPP::PSD::DPPAlgorithmControl2_G, ch);
chkDisableOppositePulse[ID][ch]->setChecked( Digitizer::ExtractBits(dpp2, DPP::Bit_DPPAlgorithmControl_PSD::DisableOppositePolarityInhibitZeroCrossingOnCFD));
chkDisableSelfTrigger[ID][ch]->setChecked( Digitizer::ExtractBits(dpp2, DPP::Bit_DPPAlgorithmControl_PSD::DisableSelfTrigger));
chkRejPileUp[ID][ch]->setChecked( Digitizer::ExtractBits(dpp2, DPP::Bit_DPPAlgorithmControl_PSD::RejectPileup));
chkPileUpInGate[ID][ch]->setChecked( Digitizer::ExtractBits(dpp2, DPP::Bit_DPPAlgorithmControl_PSD::PileupWithinGate));
chkDisableTriggerHysteresis[ID][ch]->setChecked( Digitizer::ExtractBits(dpp2, DPP::Bit_DPPAlgorithmControl_PSD::DisableTriggerHysteresis));
chkMarkSaturation[ID][ch]->setChecked( Digitizer::ExtractBits(dpp2, DPP::PSD::Bit_DPPAlgorithmControl2::MarkSaturation));
chkResetTimestampByTRGIN[ID][ch]->setChecked( Digitizer::ExtractBits(dpp2, DPP::PSD::Bit_DPPAlgorithmControl2::ResetTimestampByTRGIN));
chkMarkSaturation[ID][ch]->setChecked( Digitizer::ExtractBits(dpp, DPP::PSD::Bit_DPPAlgorithmControl2::MarkSaturation));
chkResetTimestampByTRGIN[ID][ch]->setChecked( Digitizer::ExtractBits(dpp, DPP::PSD::Bit_DPPAlgorithmControl2::ResetTimestampByTRGIN));
UpdateComboBoxBit(cbLocalTriggerValid[ID][ch], dpp2, DPP::PSD::Bit_DPPAlgorithmControl2::LocalTrigValidMode);
UpdateComboBoxBit(cbAdditionLocalTrigValid[ID][ch], dpp2, DPP::PSD::Bit_DPPAlgorithmControl2::AdditionLocalTrigValid);

View File

@ -33,6 +33,8 @@ public slots:
void SaveSetting(int opt);
void LoadSetting();
void EnableButtons(bool enable);
signals:
void SendLogMsg(const QString &msg);
void UpdateOtherPanels();
@ -69,7 +71,6 @@ private:
void SyncComboBox(RComboBox *(&cb)[][MaxRegChannel+1]);
void SyncCheckBox(QCheckBox *(&chk)[][MaxRegChannel+1]);
void SyncAllChannelsTab_PHA();
void UpdateSettings_PHA();
void SyncAllChannelsTab_PSD();
@ -102,6 +103,8 @@ private:
QLineEdit * leSaveFilePath[MaxNDigitizer];
QWidget * buttonsWidget[MaxNDigitizer];
QPushButton * bnRefreshSetting; // read setting from board
QPushButton * bnProgramPreDefined;
QPushButton * bnClearBuffer;

7
FSUDAQ Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
timestamp=$(date +%Y%m%d_%H%M%S)
outFile=program_${timestamp}.log
stdbuf -oL ./FSUDAQ_Qt6 | tee $outFile

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#ifndef FSUDAQ_H
#define FSUDAQ_H
#include <QMainWindow>
#include <QWidget>
@ -20,12 +20,14 @@
#include "ClassInfluxDB.h"
#include "analyzers/Analyser.h"
//^#===================================================== MainWindow
class MainWindow : public QMainWindow{
class ScalarWorker; //Forward declaration
//^#===================================================== FSUDAQ
class FSUDAQ : public QMainWindow{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
FSUDAQ(QWidget *parent = nullptr);
~FSUDAQ();
void closeEvent(QCloseEvent * event){
if( scope ) {
@ -36,9 +38,9 @@ public:
delete digiSettings;
digiSettings = nullptr;
}
if( canvas ) {
delete canvas;
canvas = nullptr;
if( singleHistograms ) {
delete singleHistograms;
singleHistograms = nullptr;
}
if( onlineAnalyzer ) {
delete onlineAnalyzer;
@ -47,6 +49,9 @@ public:
event->accept();
}
public slots:
void UpdateScalar();
private slots:
void OpenDataPath();
@ -64,7 +69,6 @@ private slots:
void SetupScalar();
void CleanUpScalar();
void OpenScalar();
void UpdateScalar();
void StartACQ();
void StopACQ();
@ -76,7 +80,7 @@ private slots:
void OpenDigiSettings();
void OpenCanvas();
void OpenSingleHistograms();
void OpenAnalyzer();
@ -96,6 +100,7 @@ private:
Digitizer ** digi;
unsigned int nDigi;
bool isACQStarted;
QString programSettingsFilePath;
QString rawDataPath;
@ -145,6 +150,9 @@ private:
QLineEdit * leElogIP;
QLineEdit * leElogName;
QCheckBox * chkInflux;
QCheckBox * chkElog;
//@----- log msg
QPlainTextEdit * logInfo;
void LogMsg(QString msg);
@ -165,7 +173,13 @@ private:
//@----- Scalar
QMainWindow * scalar;
QGridLayout * scalarLayout;
TimingThread * scalarThread;
TimingThread * scalarTimingThread;
// QThread * scalarThread;
// ScalarWorker * scalarWorker;
// QTimer * scalarTimer;
// TimingThread * scalarThread;
QLineEdit *** leTrigger; // need to delete manually
QLineEdit *** leAccept; // need to delete manually
QPushButton * runStatus[MaxNDigitizer];
@ -190,14 +204,45 @@ private:
DigiSettingsPanel * digiSettings;
//@----- SingleSpectra
SingleSpectra * canvas;
TimingThread * histThread;
SingleSpectra * singleHistograms;
//@----- Analyzer
Analyzer * onlineAnalyzer;
QString maskText(const QString &password) {
if (password.length() <= 3) {
return password; // No masking needed for short passwords
} else if (password.length() <= 10) {
QString maskedPassword = password.left(3);
maskedPassword += QString("*").repeated(password.length() - 3);
return maskedPassword;
} else {
return password.left(3) + QString("*").repeated(7);
}
}
};
//^======================== Scalar Worker
// class ScalarWorker : public QObject{
// Q_OBJECT
// public:
// ScalarWorker(FSUDAQ * parent): SS(parent){}
// public slots:
// void UpdateScalar(){
// SS->UpdateScalar();
// emit workDone();
// }
// signals:
// void workDone();
// private:
// FSUDAQ * SS;
// };
#endif // MAINWINDOW_H

View File

@ -11,9 +11,9 @@ QT += core widgets charts printsupport
LIBS += -lCAENDigitizer -lcurl
#==== for enable GDB debug
#QMAKE_CXXFLAGS += -g
#QMAKE_CXXFLAGS_RELEASE = -O0
#QMAKE_CFLAGS_RELEASE = -O0
QMAKE_CXXFLAGS += -g
QMAKE_CXXFLAGS_RELEASE = -O0
QMAKE_CFLAGS_RELEASE = -O0
# You can make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
@ -25,34 +25,37 @@ LIBS += -lCAENDigitizer -lcurl
# Input
HEADERS += ClassData.h \
ClassDigitizer.h \
ClassInfluxDB.h\
CustomThreads.h \
CustomWidgets.h \
Histogram1D.h \
Histogram2D.h \
DigiSettingsPanel.h \
FSUDAQ.h \
macro.h \
RegisterAddress.h \
ClassInfluxDB.h\
Scope.h \
SingleSpectra.h \
Histogram1D.h \
Histogram2D.h \
Hit.h \
macro.h \
MultiBuilder.h \
qcustomplot.h \
analyzers/Isotope.h \
RegisterAddress.h \
Scope.h \
SingleSpectra.h \
analyzers/Analyser.h \
analyzers/BeamTune.h\
analyzers/CoincidentAnalyzer.h \
analyzers/SplitPoleAnalyzer.h \
analyzers/Cross.h\
analyzers/EncoreAnalyzer.h \
analyzers/Isotope.h \
analyzers/MCP.h \
analyzers/MCPandPSD.h \
analyzers/PID.h \
analyzers/RAISOR1.h \
analyzers/RAISOR2.h \
analyzers/TEST.h \
analyzers/MCPandPSD.h \
analyzers/MCP.h \
analyzers/Cross.h\
analyzers/SplitPoleAnalyzer.h \
analyzers/Target.h\
analyzers/BeamTune.h\
analyzers/PID.h
analyzers/TEST.h \
analyzers/MUSICAnalyzer.h \
analyzers/NeutronGamma.h
SOURCES += ClassDigitizer.cpp \
DigiSettingsPanel.cpp \
FSUDAQ.cpp \

View File

@ -15,6 +15,8 @@ public:
// DebugPrint("%s", "Histogram1D");
isLogY = false;
for( int i = 0; i < MaxNHist; i++ ) showHist[i] = true;
for( int i = 0; i < 3; i ++) txt[i] = nullptr;
nData = 1;
Rebin(xbin, xmin, xmax);
@ -86,12 +88,15 @@ public:
QAction * a1 = menu.addAction("UnZoom");
QAction * a5 = menu.addAction("Set/UnSet Log-y");
QAction * a6 = nullptr;
if( nData > 1 ) a6 = menu.addAction("Toggle lines display");
QAction * a2 = menu.addAction("Clear hist.");
QAction * a3 = menu.addAction("Toggle Stat.");
QAction * a4 = menu.addAction("Rebin (clear histogram)");
//TODO fitGuass
QAction *selectedAction = menu.exec(event->globalPosition().toPoint());
//*========================================== UnZoom
if( selectedAction == a1 ){
xAxis->setRangeLower(xMin);
xAxis->setRangeUpper(xMax);
@ -101,11 +106,13 @@ public:
usingMenu = false;
}
//*========================================== Clear Hist
if( selectedAction == a2 ){
Clear();
usingMenu = false;
}
//*========================================== Toggle Stat.
if( selectedAction == a3 ){
for( int i = 0; i < 3; i++){
txt[i]->setVisible( !txt[i]->visible());
@ -113,6 +120,7 @@ public:
replot();
usingMenu = false;
}
//*========================================== Rebin
if( selectedAction == a4 ){
QDialog dialog(this);
dialog.setWindowTitle("Rebin histogram");
@ -145,25 +153,25 @@ public:
double number[3];
QObject::connect(&buttonBox, &QDialogButtonBox::accepted, [&]() {
int OKcount = 0;
bool conversionOk = true;
for( int i = 0; i < 3; i++ ){
number[i] = lineEdit[i]->text().toDouble(&conversionOk);
if( conversionOk ){
OKcount++;
}else{
msg->setText(nameList[i] + " is invalid.");
return;
}
int OKcount = 0;
bool conversionOk = true;
for( int i = 0; i < 3; i++ ){
number[i] = lineEdit[i]->text().toDouble(&conversionOk);
if( conversionOk ){
OKcount++;
}else{
msg->setText(nameList[i] + " is invalid.");
return;
}
}
if( OKcount == 3 ) {
if( number[2] > number[1] ) {
dialog.accept();
}else{
msg->setText(nameList[2] + " is smaller than " + nameList[1]);
}
if( OKcount == 3 ) {
if( number[2] > number[1] ) {
dialog.accept();
}else{
msg->setText(nameList[2] + " is smaller than " + nameList[1]);
}
}
});
QObject::connect(&buttonBox, &QDialogButtonBox::rejected, [&]() { dialog.reject();});
@ -174,8 +182,38 @@ public:
}
}
if( selectedAction == a5 ){
//*========================================== Toggle line Display
if( selectedAction == a6 ){
QDialog dialog(this);
dialog.setWindowTitle("Toggle lines Display");
QFormLayout layout(&dialog);
QCheckBox ** cbline = new QCheckBox *[nData];
for( int i = 0; i < nData; i++ ){
cbline[i] = new QCheckBox(graph(i)->name(), &dialog);
layout.addRow(cbline[i]);
if( showHist[i] ) cbline[i]->setChecked(true);
}
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
layout.addRow(&buttonBox);
QObject::connect(&buttonBox, &QDialogButtonBox::accepted, [&]() {
for( int i = 0; i < nData; i++ ){
showHist[i] = cbline[i]->isChecked();
}
dialog.accept();
});
QObject::connect(&buttonBox, &QDialogButtonBox::rejected, [&]() { dialog.reject();});
if( dialog.exec() == QDialog::Accepted ){
UpdatePlot();
}
}
//*========================================== Set Log y
if( selectedAction == a5 ){
if( !isLogY ){
this->yAxis->setScaleType(QCPAxis::stLogarithmic);
isLogY = true;
@ -206,12 +244,16 @@ public:
addGraph();
graph(nData - 1)->setName(title);
SetColor(color, nData-1);
yList[nData-1] = yList[0];
yList[nData-1].clear();
for( int i = 0; i < xList.count(); i++) yList[nData-1].append(0);
}
void UpdatePlot(){
DebugPrint("%s", "Histogram1D");
for( int ID = 0 ; ID < nData; ID ++) graph(ID)->setData(xList, yList[ID]);
for( int ID = 0 ; ID < nData; ID ++) {
graph(ID)->setVisible(showHist[ID]);
graph(ID)->setData(xList, yList[ID]);
}
xAxis->setRangeLower(xMin);
xAxis->setRangeUpper(xMax);
yAxis->setRangeLower(0);
@ -222,7 +264,7 @@ public:
void Clear(){
DebugPrint("%s", "Histogram1D");
for( int ID = 0 ; ID < nData; ID ++) {
for( int i = 0; i <= yList[ID].count(); i++) yList[ID][i] = 0;
for( int i = 0; i < xList.count(); i++) yList[ID][i] = 0;
}
yMax = 0;
txt[0]->setText("Under Flow : 0");
@ -234,7 +276,7 @@ public:
UpdatePlot();
}
void SetXTitle(QString xTitle) { xAxis->setLabel(xTitle); }
void SetXTitle(QString xTitle) { xAxis->setLabel(xTitle);}
void Rebin(int xbin, double xmin, double xmax){
// DebugPrint("%s", "Histogram1D");
@ -283,16 +325,18 @@ public:
txt[2]->setText("Over Flow : "+ QString::number(overFlow));
return;
}
}else{
if( value < xMin || value > xMax ) return;
}
double bin = (value - xMin)/dX;
int index1 = 2*qFloor(bin) + 1;
int bin = qFloor((value - xMin)/dX);
int index1 = 2*bin + 1;
int index2 = index1 + 1;
if( 0 <= index1 && index1 <= 2*xBin) yList[ID][index1] += 1;
if( 0 <= index1 && index2 <= 2*xBin) yList[ID][index2] += 1;
if( yList[ID][index1] > yMax ) yMax = yList[ID][index1];
if( showHist[ID] && yList[ID][index1] > yMax ) yMax = yList[ID][index1];
}
void Print(unsigned int ID = 0){
@ -324,6 +368,8 @@ private:
bool usingMenu;
bool showHist[MaxNHist];
};

View File

@ -19,200 +19,20 @@ const QList<QPair<QColor, QString>> colorCycle = { {QColor(Qt::red), "Red"},
class Histogram2D : public QCustomPlot{
public:
Histogram2D(QString title, QString xLabel, QString yLabel, int xbin, double xmin, double xmax, int ybin, double ymin, double ymax, QWidget * parent = nullptr) : QCustomPlot(parent){
// DebugPrint("%s", "Histogram2D");
for( int i = 0; i < 3; i ++ ){
for( int j = 0; j < 3; j ++ ){
box[i][j] = nullptr;
txt[i][j] = nullptr;
}
}
Histogram2D(QString title, QString xLabel, QString yLabel,
int xbin, double xmin, double xmax,
int ybin, double ymin, double ymax,
QWidget * parent = nullptr,
QString defaultPath = QDir::homePath());
isChannelMap = false;
tickStep = 1; // only used when isChannelMap = true
isLogZ = false;
axisRect()->setupFullAxesBox(true);
xAxis->setLabel(xLabel);
yAxis->setLabel(yLabel);
colorMap = new QCPColorMap(xAxis, yAxis);
Rebin(xbin, xmin, xmax, ybin, ymin, ymax);
colorMap->setInterpolate(false);
QCPTextElement *titleEle = new QCPTextElement(this, title, QFont("sans", 12));
plotLayout()->insertRow(0);
plotLayout()->addElement(0, 0, titleEle);
colorScale = new QCPColorScale(this);
plotLayout()->addElement(1, 1, colorScale);
colorScale->setType(QCPAxis::atRight);
colorMap->setColorScale(colorScale);
QCPColorGradient color;
color.setNanHandling(QCPColorGradient::NanHandling::nhNanColor);
color.setNanColor(QColor("white"));
color.clearColorStops();
// color.setColorStopAt( 0.0, QColor("white" ));
color.setColorStopAt( 0.0, QColor("purple" ));
color.setColorStopAt( 0.2, QColor("blue"));
color.setColorStopAt( 0.4, QColor("cyan"));
color.setColorStopAt( 0.6, QColor("green"));
color.setColorStopAt( 0.8, QColor("yellow"));
color.setColorStopAt( 1.0, QColor("red"));
colorMap->setGradient(color);
double xPosStart = 0.02;
double xPosStep = 0.07;
double yPosStart = 0.02;
double yPosStep = 0.05;
for( int i = 0; i < 3; i ++ ){
for( int j = 0; j < 3; j ++ ){
box[i][j] = new QCPItemRect(this);
box[i][j]->topLeft->setType(QCPItemPosition::ptAxisRectRatio);
box[i][j]->topLeft->setCoords(xPosStart + xPosStep*i, yPosStart + yPosStep*j);
box[i][j]->bottomRight->setType(QCPItemPosition::ptAxisRectRatio);
box[i][j]->bottomRight->setCoords(xPosStart + xPosStep*(i+1), yPosStart + yPosStep*(j+1));
txt[i][j] = new QCPItemText(this);
txt[i][j]->setPositionAlignment(Qt::AlignLeft);
txt[i][j]->position->setType(QCPItemPosition::ptAxisRectRatio);
txt[i][j]->position->setCoords(xPosStart + xPosStep/2 + xPosStep*i, yPosStart + yPosStep*j);;
txt[i][j]->setText("0");
txt[i][j]->setFont(QFont("Helvetica", 9));
}
}
cutList.clear();
cutEntryList.clear();
rescaleAxes();
usingMenu = false;
isDrawCut = false;
tempCutID = -1;
numCut = 0;
lastPlottableID = -1;
line = new QCPItemLine(this);
line->setPen(QPen(Qt::gray, 1, Qt::DashLine));
line->setVisible(false);
isBusy = false;
connect(this, &QCustomPlot::mouseMove, this, [=](QMouseEvent *event){
double x = xAxis->pixelToCoord(event->pos().x());
double y = yAxis->pixelToCoord(event->pos().y());
int xI, yI;
colorMap->data()->coordToCell(x, y, &xI, &yI);
double z = colorMap->data()->cell(xI, yI);
QString coordinates = QString("X: %1, Y: %2, Z: %3").arg(x).arg(y).arg(z);
QToolTip::showText(event->globalPosition().toPoint(), coordinates, this);
//when drawing cut, show dashhed line
if( isDrawCut && tempCut.size() > 0 ){
line->end->setCoords(x,y);
line->setVisible(true);
replot();
}
});
connect(this, &QCustomPlot::mousePress, this, [=](QMouseEvent * event){
if (event->button() == Qt::LeftButton && !usingMenu && !isDrawCut){
setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
}
if (event->button() == Qt::LeftButton && isDrawCut){
oldMouseX = xAxis->pixelToCoord(event->pos().x());
oldMouseY = yAxis->pixelToCoord(event->pos().y());
tempCut.push_back(QPointF(oldMouseX,oldMouseY));
line->start->setCoords(oldMouseX, oldMouseY);
line->end->setCoords(oldMouseX, oldMouseY);
line->setVisible(true);
DrawCut();
}
//^================= right click
if (event->button() == Qt::RightButton) rightMouseClickMenu(event);
});
//connect( this, &QCustomPlot::mouseDoubleClick, this, [=](QMouseEvent *event){
connect( this, &QCustomPlot::mouseDoubleClick, this, [=](){
if( isDrawCut) {
tempCut.push_back(tempCut[0]);
DrawCut();
isDrawCut = false;
line->setVisible(false);
plottableIDList.push_back(plottableCount() -1 );
cutNameList.push_back("Cut-" + QString::number(cutList.count()));
cutEntryList.push_back(0);
QCPItemText * text = new QCPItemText(this);
text->setText(cutNameList.last());
text->position->setCoords(tempCut[0].rx(), tempCut[0].ry());
int colorID = tempCutID% colorCycle.count();
text->setColor(colorCycle[colorID].first);
cutTextIDList.push_back(itemCount() - 1);
replot();
cutList.push_back(tempCut);
cutIDList.push_back(tempCutID);
// qDebug() << "----------- end of create cut";
// qDebug() << " cutIDList " << cutIDList ;
// qDebug() << "plottableIDList " << plottableIDList << ", " << plottableCount();
// qDebug() << " cutTextIDList " << cutTextIDList << ", " << itemCount();
}
});
connect(this, &QCustomPlot::mouseRelease, this, [=](){
});
}
//^===================================
void SetXTitle(QString xTitle) { xAxis->setLabel(xTitle); }
void SetYTitle(QString yTitle) { yAxis->setLabel(yTitle); }
void SetXTitle(QString xTitle) { xAxis->setLabel(xTitle);}
void SetYTitle(QString yTitle) { yAxis->setLabel(yTitle);}
void Rebin(int xbin, double xmin, double xmax, int ybin, double ymin, double ymax);
void RebinY(int ybin, double ymin, double ymax);
void SetChannelMap(bool onOff, int tickStep = 1) { isChannelMap = onOff; this->tickStep = tickStep;}
void UpdatePlot(){
// QCPColorGradient color;
// color.clearColorStops();
// color.setNanColor(QColor("white"));
// // color.setColorStopAt( 0.0, QColor("white" ));
// // color.setColorStopAt( 1.0/entry[1][1], QColor("purple" ));
// color.setColorStopAt( 0.0, QColor("purple" ));
// color.setColorStopAt( 0.2, QColor("blue"));
// color.setColorStopAt( 0.4, QColor("cyan"));
// color.setColorStopAt( 0.6, QColor("green"));
// color.setColorStopAt( 0.8, QColor("yellow"));
// color.setColorStopAt( 1.0, QColor("red"));
// colorMap->setGradient(color);
colorMap->rescaleDataRange();
replot();
}
void UpdatePlot(){ colorMap->rescaleDataRange(); replot(); }
void Clear(); // Clear Data and histrogram
void Fill(double x, double y);
@ -232,6 +52,9 @@ public:
double GetYMin() const {return yMin;}
double GetYMax() const {return yMax;}
void SaveCuts(QString cutFileName);
void LoadCuts(QString cutFileName);
private:
double xMin, xMax, yMin, yMax;
int xBin, yBin;
@ -252,15 +75,15 @@ private:
QPolygonF tempCut;
int tempCutID; // only incresing;
QList<QPolygonF> cutList;
QList<int> cutIDList;
int numCut;
QList<QPolygonF> cutList;
QList<QString> cutNameList; // name of the cut
QList<int> cutEntryList; // number of entry inside the cut.
QList<int> cutIDList; // ID of the cut
QList<int> cutTextIDList; //
QList<int> plottableIDList;
bool isDrawCut;
int lastPlottableID;
QList<int> cutTextIDList;
QList<int> plottableIDList;
QList<QString> cutNameList;
QList<int> cutEntryList;
QCPItemLine * line;
double oldMouseX = 0.0, oldMouseY = 0.0;
@ -270,11 +93,183 @@ private:
void rightMouseClickMenu(QMouseEvent * event);
void rightMouseClickRebin();
QString settingPath;
};
//^###############################################
//^###############################################
inline Histogram2D::Histogram2D(QString title, QString xLabel, QString yLabel, int xbin, double xmin, double xmax, int ybin, double ymin, double ymax, QWidget * parent, QString defaultPath) : QCustomPlot(parent){
// DebugPrint("%s", "Histogram2D");
settingPath = defaultPath;
for( int i = 0; i < 3; i ++ ){
for( int j = 0; j < 3; j ++ ){
box[i][j] = nullptr;
txt[i][j] = nullptr;
}
}
isChannelMap = false;
tickStep = 1; // only used when isChannelMap = true
isLogZ = false;
axisRect()->setupFullAxesBox(true);
xAxis->setLabel(xLabel);
yAxis->setLabel(yLabel);
colorMap = new QCPColorMap(xAxis, yAxis);
Rebin(xbin, xmin, xmax, ybin, ymin, ymax);
colorMap->setInterpolate(false);
QCPTextElement *titleEle = new QCPTextElement(this, title, QFont("sans", 12));
plotLayout()->insertRow(0);
plotLayout()->addElement(0, 0, titleEle);
colorScale = new QCPColorScale(this);
plotLayout()->addElement(1, 1, colorScale);
colorScale->setType(QCPAxis::atRight);
colorMap->setColorScale(colorScale);
QCPColorGradient color;
color.setNanHandling(QCPColorGradient::NanHandling::nhNanColor);
color.setNanColor(QColor("white"));
color.clearColorStops();
// color.setColorStopAt( 0.0, QColor("white" ));
color.setColorStopAt( 0.0, QColor("purple" ));
color.setColorStopAt( 0.2, QColor("blue"));
color.setColorStopAt( 0.4, QColor("cyan"));
color.setColorStopAt( 0.6, QColor("green"));
color.setColorStopAt( 0.8, QColor("yellow"));
color.setColorStopAt( 1.0, QColor("red"));
colorMap->setGradient(color);
double xPosStart = 0.02;
double xPosStep = 0.07;
double yPosStart = 0.02;
double yPosStep = 0.05;
for( int i = 0; i < 3; i ++ ){
for( int j = 0; j < 3; j ++ ){
box[i][j] = new QCPItemRect(this);
box[i][j]->topLeft->setType(QCPItemPosition::ptAxisRectRatio);
box[i][j]->topLeft->setCoords(xPosStart + xPosStep*i, yPosStart + yPosStep*j);
box[i][j]->bottomRight->setType(QCPItemPosition::ptAxisRectRatio);
box[i][j]->bottomRight->setCoords(xPosStart + xPosStep*(i+1), yPosStart + yPosStep*(j+1));
txt[i][j] = new QCPItemText(this);
txt[i][j]->setPositionAlignment(Qt::AlignLeft);
txt[i][j]->position->setType(QCPItemPosition::ptAxisRectRatio);
txt[i][j]->position->setCoords(xPosStart + xPosStep/2 + xPosStep*i, yPosStart + yPosStep*j);;
txt[i][j]->setText("0");
txt[i][j]->setFont(QFont("Helvetica", 9));
}
}
cutList.clear();
cutEntryList.clear();
rescaleAxes();
usingMenu = false;
isDrawCut = false;
tempCutID = -1;
numCut = 0;
lastPlottableID = -1;
line = new QCPItemLine(this);
line->setPen(QPen(Qt::gray, 1, Qt::DashLine));
line->setVisible(false);
isBusy = false;
connect(this, &QCustomPlot::mouseMove, this, [=](QMouseEvent *event){
double x = xAxis->pixelToCoord(event->pos().x());
double y = yAxis->pixelToCoord(event->pos().y());
int xI, yI;
colorMap->data()->coordToCell(x, y, &xI, &yI);
double z = colorMap->data()->cell(xI, yI);
QString coordinates = QString("X: %1, Y: %2, Z: %3").arg(x).arg(y).arg(z);
QToolTip::showText(event->globalPosition().toPoint(), coordinates, this);
//when drawing cut, show dashhed line
if( isDrawCut && tempCut.size() > 0 ){
line->end->setCoords(x,y);
line->setVisible(true);
replot();
}
});
connect(this, &QCustomPlot::mousePress, this, [=](QMouseEvent * event){
if (event->button() == Qt::LeftButton && !usingMenu && !isDrawCut){
setSelectionRectMode(QCP::SelectionRectMode::srmZoom);
}
if (event->button() == Qt::LeftButton && isDrawCut){
oldMouseX = xAxis->pixelToCoord(event->pos().x());
oldMouseY = yAxis->pixelToCoord(event->pos().y());
tempCut.push_back(QPointF(oldMouseX,oldMouseY));
line->start->setCoords(oldMouseX, oldMouseY);
line->end->setCoords(oldMouseX, oldMouseY);
line->setVisible(true);
DrawCut();
}
//^================= right click
if (event->button() == Qt::RightButton) rightMouseClickMenu(event);
});
//connect( this, &QCustomPlot::mouseDoubleClick, this, [=](QMouseEvent *event){
connect( this, &QCustomPlot::mouseDoubleClick, this, [=](){
if( isDrawCut) {
tempCut.push_back(tempCut[0]);
DrawCut();
isDrawCut = false;
line->setVisible(false);
plottableIDList.push_back(plottableCount() -1 );
cutNameList.push_back("Cut-" + QString::number(cutList.count()));
cutEntryList.push_back(0);
QCPItemText * text = new QCPItemText(this);
text->setText(cutNameList.last());
text->position->setCoords(tempCut[0].rx(), tempCut[0].ry());
int colorID = tempCutID% colorCycle.count();
text->setColor(colorCycle[colorID].first);
cutTextIDList.push_back(itemCount() - 1);
replot();
cutList.push_back(tempCut);
cutIDList.push_back(tempCutID);
// qDebug() << "----------- end of create cut";
// qDebug() << " cutIDList " << cutIDList ;
// qDebug() << "plottableIDList " << plottableIDList << ", " << plottableCount();
// qDebug() << " cutTextIDList " << cutTextIDList << ", " << itemCount();
}
});
connect(this, &QCustomPlot::mouseRelease, this, [=](){
});
}
inline void Histogram2D::Fill(double x, double y){
// DebugPrint("%s", "Histogram2D");
if( isBusy ) return;
@ -338,6 +333,9 @@ inline void Histogram2D::Rebin(int xbin, double xmin, double xmax, int ybin, do
}
}
rescaleAxes();
UpdatePlot();
}
inline void Histogram2D::RebinY(int ybin, double ymin, double ymax){
@ -388,7 +386,7 @@ inline void Histogram2D::ClearAllCuts(){
inline void Histogram2D::PrintCutEntry() const{
DebugPrint("%s", "Histogram2D");
if( numCut == 0 ) return;
printf("=============== There are %d cuts.\n", numCut);
printf("=============== There are %d cuts. (%lld, %lld)\n", numCut, cutList.count(), cutEntryList.count());
for( int i = 0; i < cutList.count(); i++){
if( cutList[i].isEmpty() ) continue;
printf("%10s | %d \n", cutNameList[i].toStdString().c_str(), cutEntryList[i]);
@ -420,7 +418,7 @@ inline void Histogram2D::DrawCut(){
}
replot();
//qDebug() << "Plottable count : " << plottableCount() << ", cutList.count :" << cutList.count() << ", cutID :" << lastPlottableID;
// qDebug() << "Plottable count : " << plottableCount() << ", cutList.count :" << cutList.count() << ", cutID :" << lastPlottableID;
}
inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){
@ -436,8 +434,11 @@ inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){
QAction * a2 = menu->addAction("Clear hist.");
QAction * a3 = menu->addAction("Toggle Stat.");
QAction * a4 = menu->addAction("Rebin (clear histogram)");
QAction * a8 = menu->addAction("Load Cut(s)");
QAction * a5 = menu->addAction("Create a Cut");
QAction * a7 = nullptr;
if( numCut > 0 ) {
a7 = menu->addAction("Save Cut(s)");
menu->addSeparator();
menu->addAction("Add/Edit names to Cuts");
menu->addAction("Clear all Cuts");
@ -572,6 +573,27 @@ inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){
return;
}
if( selectedAction == a8 ){ // load Cuts
QString filePath = QFileDialog::getOpenFileName(this,
"Load Cuts from File",
settingPath,
"Text file (*.txt)");
if (!filePath.isEmpty()) LoadCuts(filePath);
}
if( selectedAction == a7 ){ // Save Cuts
QString filePath = QFileDialog::getSaveFileName(this,
"Save Cuts to File",
settingPath,
"Text file (*.txt)");
if (!filePath.isEmpty()) SaveCuts(filePath);
}
}
@ -593,7 +615,7 @@ inline void Histogram2D::rightMouseClickRebin(){
lineEditX[i] = new QLineEdit(&dialog);
layout.addRow(nameListX[i] + " : ", lineEditX[i]);
}
lineEditX[0]->setText(QString::number(xBin));
lineEditX[0]->setText(QString::number(xBin-2));
lineEditX[1]->setText(QString::number(xMin));
lineEditX[2]->setText(QString::number(xMax));
@ -603,7 +625,7 @@ inline void Histogram2D::rightMouseClickRebin(){
lineEditY[i] = new QLineEdit(&dialog);
layout.addRow(nameListY[i] + " : ", lineEditY[i]);
}
lineEditY[0]->setText(QString::number(yBin));
lineEditY[0]->setText(QString::number(yBin-2));
lineEditY[1]->setText(QString::number(yMin));
lineEditY[2]->setText(QString::number(yMax));
@ -666,12 +688,120 @@ inline void Histogram2D::rightMouseClickRebin(){
if( dialog.exec() == QDialog::Accepted ){
isBusy = true;
Rebin((int)number[0][0], number[1][0], number[2][0], (int)number[0][1], number[1][1], number[2][1]);
rescaleAxes();
UpdatePlot();
isBusy = false;
}
}
inline void Histogram2D::SaveCuts(QString cutFileName){
QFile file(cutFileName);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&file);
// Define the text to write
QStringList lines;
for( int i = 0; i < cutList.size(); i++){
lines << "====== "+ cutNameList[i];
for( int pt = 0 ; pt < cutList[i].size(); pt ++){
lines << QString::number(cutList[i][pt].rx(), 'g', 5) + "," + QString::number(cutList[i][pt].ry(), 'g', 5);
}
}
lines << "#===== End of File";
// Write each line to the file
for (const QString &line : lines) out << line << "\n";
// Close the file
file.close();
qDebug() << "File written successfully to" << cutFileName;
}else{
qWarning() << "Unable to open file" << cutFileName;
}
}
inline void Histogram2D::LoadCuts(QString cutFileName){
QFile file(cutFileName);
QString cutNameTemp;
// Open the file in read mode
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
ClearAllCuts();
tempCut.clear();
// Read each line and append to the QStringList
while (!in.atEnd()) {
QString line = in.readLine();
if( line.contains("======") ){
if( !tempCut.isEmpty() ) {
DrawCut();
plottableIDList.push_back(plottableCount() -1 );
cutNameList.push_back(cutNameTemp);
cutEntryList.push_back(0);
QCPItemText * text = new QCPItemText(this);
text->setText(cutNameList.last());
text->position->setCoords(tempCut[0].rx(), tempCut[0].ry());
int colorID = tempCutID% colorCycle.count();
text->setColor(colorCycle[colorID].first);
cutTextIDList.push_back(itemCount() - 1);
// cutList.push_back(tempCut);
cutIDList.push_back(tempCutID);
}
tempCut.clear();
tempCutID ++;
numCut ++;
int spacePos = line.indexOf(' ');
cutNameTemp = line.mid(spacePos + 1);
continue;
}
if( line.contains("#==") ) {
DrawCut();
plottableIDList.push_back(plottableCount() -1 );
cutNameList.push_back(cutNameTemp);
cutEntryList.push_back(0);
QCPItemText * text = new QCPItemText(this);
text->setText(cutNameList.last());
text->position->setCoords(tempCut[0].rx(), tempCut[0].ry());
int colorID = tempCutID% colorCycle.count();
text->setColor(colorCycle[colorID].first);
cutTextIDList.push_back(itemCount() - 1);
cutList.push_back(tempCut);
cutIDList.push_back(tempCutID);
break;
}else{
QStringList haha = line.split(",");
// qDebug() << haha;
if( haha.size() == 2 ){
tempCut.push_back(QPointF(haha[0].toFloat(), haha[1].toFloat()));
DrawCut();
}
}
}
// Close the file
file.close();
qDebug() << "File read successfully from" << cutFileName;
// PrintCutEntry();
// DrawCut();
replot();
} else {
qWarning() << "Unable to open file" << cutFileName;
}
}
#endif

View File

@ -7,15 +7,18 @@ MultiBuilder::MultiBuilder(Data ** multiData, std::vector<int> type, std::vector
data = multiData;
typeList = type;
snList = sn;
numTotCh = 0;
for( uShort i = 0; i < nData; i++) {
idList.push_back(i);
dataSize.push_back(data[i]->GetDataSize());
numTotCh += data[i]->GetNChannel();
}
timeWindow = 100;
leftOverTime = 100;
breakTime = -1;
timeJump = 1e8;
lastEventTime = 0;
forceStop = false;
ClearEvents();
@ -29,6 +32,7 @@ MultiBuilder::MultiBuilder(Data * singleData, int type, int sn): nData(1){
DebugPrint("%s", "MultiBuilder");
data = new Data *[1];
data[0] = singleData;
numTotCh = data[0]->GetNChannel();
typeList.push_back(type);
snList.push_back(sn);
idList.push_back(0);
@ -37,7 +41,7 @@ MultiBuilder::MultiBuilder(Data * singleData, int type, int sn): nData(1){
breakTime = -1;
timeJump = 1e8;
lastEventTime = 0;
forceStop = false;
ClearEvents();
}
@ -57,6 +61,7 @@ void MultiBuilder::ClearEvents(){
loopIndex[i][j] = 0;
nextIndex[i][j] = -1;
chExhaused[i][j] = false;
lastBackWardIndex[i][j] = 0;
}
earlistDigi = -1;
@ -77,7 +82,6 @@ void MultiBuilder::PrintStat(){
if( nextIndex[i][ch] >= 0 ) printf("%d %3d %2d | %7d (%d)\n", i, snList[i], ch, nextIndex[i][ch], loopIndex[i][ch]);
}
}
}
void MultiBuilder::PrintAllEvent(){
@ -89,7 +93,6 @@ void MultiBuilder::PrintAllEvent(){
events[i][j].Print();
}
}
}
void MultiBuilder::FindEarlistTimeAndCh(bool verbose){
@ -100,22 +103,26 @@ void MultiBuilder::FindEarlistTimeAndCh(bool verbose){
nExhaushedCh = 0;
for( int i = 0; i < nData; i++){
for( int j = 0; j < data[i]->GetNChannel(); j++ ) chExhaused[i][j] = false;
for( int j = 0; j < data[i]->GetNChannel(); j++ ) {
chExhaused[i][j] = false;
}
for(unsigned int ch = 0; ch < data[i]->GetNChannel(); ch ++){
int index = data[i]->GetDataIndex(ch);
if( ch >= data[i]->GetNChannel() || index < 0 ) {
nExhaushedCh ++;
chExhaused[i][ch] = true;
continue;
}
{// check is dataIndex is valid
int index = data[i]->GetDataIndex(ch);
if( index < 0 ) {
nExhaushedCh ++;
chExhaused[i][ch] = true;
continue;
}
if( data[i]->GetTimestamp(ch, index) == 0 ||
loopIndex[i][ch] * dataSize[i] > data[i]->GetLoopIndex(ch) * dataSize[i] + data[i]->GetDataIndex(ch)) {
nExhaushedCh ++;
chExhaused[i][ch] = true;
continue;
if( data[i]->GetTimestamp(ch, index) == 0 ||
loopIndex[i][ch] * dataSize[i] > data[i]->GetLoopIndex(ch) * dataSize[i] + data[i]->GetDataIndex(ch)) {
nExhaushedCh ++;
chExhaused[i][ch] = true;
continue;
}
}
if( nextIndex[i][ch] == -1 ) nextIndex[i][ch] = 0;
@ -126,6 +133,7 @@ void MultiBuilder::FindEarlistTimeAndCh(bool verbose){
earlistDigi = i;
earlistCh = ch;
}
// printf(" ch : %d | time %llu | %llu\n", ch, time, earlistTime);
}
}
@ -145,9 +153,9 @@ void MultiBuilder::FindLatestTimeAndCh(bool verbose){
for( int j = 0; j < data[i]->GetNChannel(); j++ ) chExhaused[i][j] = false;
for(unsigned int ch = 0; ch < MaxNChannels; ch ++){
for(unsigned int ch = 0; ch < data[i]->GetNChannel(); ch ++){
if( nextIndex[i][ch] < 0 || ch >= data[i]->GetNChannel() || data[i]->GetDataIndex(ch) < 0 ) {
if( nextIndex[i][ch] < 0 || data[i]->GetDataIndex(ch) < 0 || nextIndex[i][ch] <= lastBackWardIndex[i][ch] ) {
nExhaushedCh ++;
chExhaused[i][ch] = true;
// printf(", exhanshed. %d \n", nExhaushedCh);
@ -211,7 +219,8 @@ void MultiBuilder::FindLatestTimeOfData(bool verbose){
void MultiBuilder::BuildEvents(bool isFinal, bool skipTrace, bool verbose){
DebugPrint("%s", "MultiBuilder");
FindEarlistTimeAmongLastData(verbose); // give lastest Time, Ch, and Digi
FindEarlistTimeAmongLastData(verbose); // give lastest Time, Ch, and Digi for event building
FindEarlistTimeAndCh(verbose); //Give the earliest time, ch, digi
if( earlistCh == -1 || nExhaushedCh == nData * MaxNChannels) return; /// no data
@ -221,13 +230,12 @@ void MultiBuilder::BuildEvents(bool isFinal, bool skipTrace, bool verbose){
Hit em;
do{
if( forceStop ) break;
eventIndex ++;
if( eventIndex >= MaxNEvent ) eventIndex = 0;
events[eventIndex].clear();
eventBuilt ++;
totalEventBuilt ++;
em.Clear();
for( int k = 0; k < nData; k++){
@ -279,6 +287,8 @@ void MultiBuilder::BuildEvents(bool isFinal, bool skipTrace, bool verbose){
if( timeWindow <= 0 ) break;
}
if( events[eventIndex].size() == 0 ) continue;
if( events[eventIndex].size() > 1) {
std::sort(events[eventIndex].begin(), events[eventIndex].end(), [](const Hit& a, const Hit& b) {
return a.timestamp < b.timestamp;
@ -293,14 +303,17 @@ void MultiBuilder::BuildEvents(bool isFinal, bool skipTrace, bool verbose){
// //if there is a time jump, say, bigger than TimeJump. break
if( earlistTime - lastEventTime > timeJump ) {
if( verbose ){
printf("%6lu, %16llu\n", eventIndex, earlistTime);
printf("%5s - %16llu \n", "", lastEventTime);
printf("%5s > %16llu \n", "", timeJump);
printf("!!!!!!!! Time Jump detected stop event building. stop event buinding and get more data.\n");
printf("!!!!!!!! Time Jump detected stop event building and get more data.\n");
printf("event index : %6lu, earlist time : %16llu\n", eventIndex, earlistTime);
printf(" %6s last event time : %16llu \n", "", lastEventTime);
printf(" %6s time jump > %16llu \n", "", timeJump);
}
return;
}
eventBuilt ++;
totalEventBuilt ++;
if( verbose ){
printf(">>>>>>>>>>>>>>>>> Event ID : %ld, total built: %ld, multiplicity : %ld\n", eventIndex, totalEventBuilt, events[eventIndex].size());
for( int i = 0; i <(int) events[eventIndex].size(); i++){
@ -337,13 +350,16 @@ void MultiBuilder::BuildEvents(bool isFinal, bool skipTrace, bool verbose){
}
}while(nExhaushedCh < nData * MaxNChannels);
forceStop = false;
}
void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){
DebugPrint("%s", "MultiBuilder");
//skip trace, and only build for maxNumEvent events max
// remember the end of DataIndex, prevent over build
// Get the last data index and loop index
for( int k = 0; k < nData; k++){
for( int i = 0; i < data[k]->GetNChannel(); i++){
nextIndex[k][i] = data[k]->GetDataIndex(i);
@ -357,12 +373,11 @@ void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){
eventBuilt = 0;
Hit em;
do{
if( forceStop ) break;
eventIndex ++;
if( eventIndex >= MaxNEvent ) eventIndex = 0;
events[eventIndex].clear();
eventBuilt ++;
totalEventBuilt ++;
em.Clear();
for( int k = 0; k < nData; k++){
@ -373,10 +388,9 @@ void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){
for( int i = 0; i < numCh; i++){
int ch = (i + latestCh) % numCh;
if( chExhaused[bd][ch] ) continue;
//if( nextIndex[bd][ch] <= lastBackWardIndex[bd][ch] || nextIndex[bd][ch] < 0){
if( nextIndex[bd][ch] < 0){
chExhaused[bd][ch] = true;
if( nextIndex[bd][ch] <= lastBackWardIndex[bd][ch] || nextIndex[bd][ch] <= 0){
nExhaushedCh ++;
chExhaused[bd][ch] = true;
continue;
}
@ -404,12 +418,27 @@ void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){
if( timeWindow == 0 ) break;
}
std::sort(events[eventIndex].begin(), events[eventIndex].end(), [](const Hit& a, const Hit& b) {
return a.timestamp < b.timestamp;
});
FindLatestTimeAndCh(verbose);
if( verbose ) printf(" nExhaushedCh %d | numToCh %d \n", nExhaushedCh, numTotCh);
if( nExhaushedCh == numTotCh ) {
if( verbose ) printf("######################### no more event to be built\n");
break;
}
if( verbose ) printf("----- next bd: %d, ch : %d, next latest Time : %llu.\n", latestDigi, latestCh, latestTime);
if( events[eventIndex].size() > 0 ) {
eventBuilt ++;
totalEventBuilt ++;
std::sort(events[eventIndex].begin(), events[eventIndex].end(), [](const Hit& a, const Hit& b) {
return a.timestamp < b.timestamp;
});
}else{
continue;
}
if( verbose ){
printf(">>>>>>>>>>>>>>>>> Event ID : %ld, total built: %ld, multiplicity : %ld\n", eventIndex, totalEventBuilt, events[eventIndex].size());
for( int i = 0; i <(int) events[eventIndex].size(); i++){
@ -422,24 +451,19 @@ void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){
break;
}
}
printf("%05d, %02d | %5d | %5d %llu \n", sn, chxxx, nextIndex[bd][chxxx], events[eventIndex][i].energy, events[eventIndex][i].timestamp);
printf("%5d, %02d | %5d | %5d %llu \n", sn, chxxx, nextIndex[bd][chxxx], events[eventIndex][i].energy, events[eventIndex][i].timestamp);
}
if( nExhaushedCh == nData * MaxNChannels ) {
printf("######################### no more event to be built\n");
break;
}
printf("----- next bd: %d, ch : %d, next latest Time : %llu.\n", latestDigi, latestCh, latestTime);
}
}while(nExhaushedCh < nData * MaxNChannels && eventBuilt < maxNumEvent);
}while(nExhaushedCh < numTotCh && eventBuilt < maxNumEvent);
// // remember the end of DataIndex, prevent over build
// for( int k = 0; k < nData; k++){
// for( int i = 0; i < MaxRegChannel; i++){
// lastBackWardIndex[k][i] = data[k]->DataIndex[i];
// }
// }
forceStop = false;
// remember the end of DataIndex, prevent over build
for( int k = 0; k < nData; k++){
for( int i = 0; i < data[k]->GetNChannel(); i++){
lastBackWardIndex[k][i] = data[k]->GetDataIndex(i);
}
}
}

View File

@ -14,16 +14,18 @@ public:
MultiBuilder(Data * singleData, int type, int sn);
~MultiBuilder();
void SetTimeWindow(unsigned short ticks) {timeWindow = ticks; leftOverTime = ticks;}
void ForceStop(bool onOff) { forceStop = onOff;}
void SetTimeWindow(unsigned short nanosec) {timeWindow = nanosec; leftOverTime = nanosec;}
unsigned short GetTimeWindow() const{return timeWindow;}
void SetTimeJump(unsigned long long TimeJumpInNanoSec) {timeJump = TimeJumpInNanoSec;}
unsigned long long GetTimeJump() const {return timeJump;}
void SetLeftOverTime(unsigned long long ticks) {leftOverTime = ticks;}
void SetLeftOverTime(unsigned long long nanosec) {leftOverTime = nanosec;}
unsigned long long GetLeftOverTime() const{return leftOverTime;}
void SetBreakTime(unsigned long long ticks) {breakTime = ticks;}
void SetBreakTime(unsigned long long nanosec) {breakTime = nanosec;}
unsigned long long GetBreakTime() const{return breakTime;}
unsigned int GetNumOfDigitizer() const {return nData;}
@ -48,6 +50,7 @@ private:
std::vector<int> tick2ns;
const unsigned short nData;
Data ** data; // assume all data has MaxNChannel (16)
int numTotCh; // number of total channel = sum digi[i]->GetNChannel()
std::vector<uShort> dataSize;
@ -78,6 +81,8 @@ private:
int lastBackWardIndex[MaxNDigitizer][MaxNChannels];
bool forceStop;
};

View File

@ -6,19 +6,19 @@ https://discord.gg/xVsRhNZF8G
This is a DAQ for 1st gen CAEN digitizer for
- V1725, V17255S, V1230 with PHA and PSD firmware.
- x725, x725S, x730 with PHA and PSD firmware.
- V1740 with QDC firmware
It has scope (updated every half-sec), allow full control of the digitizer (except LVDS), and allow saving waveform.
It can be connected to InfluxDB v1.8+ and Elog.
Each channel has it own 1D histogram. It will not be filled by default, but can enable it in the "Online 1D histgram" panel. The binning of each histogram will be saved under the raw data path as singleSpectaSetting.txt
Each channel has it own 1D histogram. It will not be filled by default, but can enable it in the "Online Histgrams" panel. The binning of each histogram will be saved under the raw data path as singleSpectaSetting.txt
## Wiki
https://fsunuc.physics.fsu.edu/wiki/index.php/CAEN_digitizer
## Online analyzer
# Online analyzer
A Multi-builder (event builder that can build event across multiple digitizer) is made. It has normal event building code and also a backward event building code that build events from the latest data up to certain amont of event.
A 1-D and 2-D histogram is avalible. In the 2-D histogram, graphical cuts can be created and rename.
@ -27,6 +27,25 @@ An online analyzer class is created as a template for online analysis. An exampl
<span style="color:red;">Notice that, when the FSUDAQ is started, the online analyzer is not created, no event will be built. Once the online anlyzer is created and opened, event will be built, even the window is closed. </span>
## Create a custom online analyzer
Under the analyzer folder, there are few examples can be followed. Teh idea is create a derivative class based on the Analyzer.h. To implement the new online analyzer, user need to modify a few things:
- add the code file into FSUDAQ_At.pro
- add the header to the top of FSUDAQ.cpp
- edit the vector onlienAnalyzerList at th etop of FSUDAQ.cpp
- edit the FSUDAQ::OpenAnalyzer()
after that, we need to update the makefile by
```sh
>qmake6 FSUDAQ_Qt6.pro
```
and then recompile by
```sh
>make
```
# Operation
When programSettings.txt is presented in the same folder as the FSUDAQ_Qt, the program will load it can config the following
@ -65,8 +84,7 @@ User must setup the data path for data take. Without the data path, user still c
# ToDo
- Gaussians fitting for 1D Histogram
- Improve the color scheme for 2D histogram
- Gaussians fitting for 1D Histogra
- Save Histogram?
# Required / Development enviroment
@ -77,6 +95,7 @@ Ubuntu 22.04
- CAENCOmm v1.5.3 +
- CAENDigitizer v2.17.1 +
- CAEN A3818 Driver v1.6.8 +
- CAENUSBdrv v1.5.5 + (for V57XX digitizer with USB connection)
- qt6-base-dev
- libqt6charts6-dec
@ -135,13 +154,28 @@ if you want to use GDB debugger, in the *.pro file add
` QMAKE_CXXFLAGS += -g`
# Auxillary programs (e.g. Event Builder)
There is a folder Aux, this folder contains many auxillary programs, such as EventBuilder. User can `make` under the folder to compile the programs.
# Tested Trigger Rate
# Enable Core dump
The program has abort handler to save core dump.
first, enable the gdb in compilation by edit the FSUDAQ_Qt6.pro by commen out the following lines:
```sh
QMAKE_CXXFLAGS += -g
QMAKE_CXXFLAGS_RELEASE = -O0
QMAKE_CFLAGS_RELEASE = -O0
```
second, ensure the core dump file has unlimited size and set the core dump file name
```sh
>ulimit -c unlimited
>echo "core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern
```
* V1725, 1 MHz to 3 ch (decay = 500 ns), no trace. need to set Agg/Read = 100 and Evt/Agg = 511.
# Known Issues
@ -150,10 +184,10 @@ There is a folder Aux, this folder contains many auxillary programs, such as Eve
* When using the scope, the Agg/Read must be smaller than 512.
* Although the Events/Agg used the CAEN API to recalculate before ACQ start, for PHA firmware, when the trigger rate changed, the Events per Agg need to be changed.
* The Agg Organization, Event per Agg, Record Length are strongly correlated. Some settings are invalid and will cause the digitizer goes crazy.
* load digitizer setting would not load everything, only load the channel settings and some board settings.
* Load digitizer setting would not load everything, only load the channel settings and some board settings.
* Sometimes, the buffer is not in time order, and make the trigger/Accept rate to be nagative. This is nothing to do with the program but the digitizer settings. Recommand reporgram the digitizer.
* for 1740 QDC, RecordLenght is board setting, but readout is indivuial group.
* FOr PHA, the trapezoid scaling and fine-gain register are calculated before ACQ start.
* For 1740 QDC, RecordLenght is board setting, but readout is indivuial group.
* For PHA, the trapezoid scaling and fine-gain register are calculated before ACQ start.
# Known Bugs

View File

@ -6,6 +6,7 @@
#include <QGroupBox>
#include <QStandardItemModel>
#include <QLabel>
#include <QScreen>
QVector<QPointF> Scope::TrapezoidFilter(QVector<QPointF> data, int baseLineEndS, int riseTimeS, int flatTopS, float decayTime_ns){
DebugPrint("%s", "Scope");
@ -40,12 +41,12 @@ QVector<QPointF> Scope::TrapezoidFilter(QVector<QPointF> data, int baseLineEndS,
trapezoid.append(QPointF(data[i].x(), sn / decayTime_ns / riseTimeS));
}
}
return trapezoid;
}
//^========================================================
//^========================================================
Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataThread, QMainWindow * parent) : QMainWindow(parent){
DebugPrint("%s", "Scope");
this->digi = digi;
@ -53,9 +54,17 @@ Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataTh
this->readDataThread = readDataThread;
setWindowTitle("Scope");
setGeometry(0, 0, 1000, 800);
setWindowFlags( this->windowFlags() & ~Qt::WindowCloseButtonHint );
//====== resize window if screen too small
QScreen * screen = QGuiApplication::primaryScreen();
QRect screenGeo = screen->geometry();
if( screenGeo.width() < 1000 || screenGeo.height() < 800) {
setGeometry(0, 0, screenGeo.width() - 100, screenGeo.height() - 100);
}else{
setGeometry(0, 0, 1000, 800);
}
enableSignalSlot = false;
isACQStarted = false;
@ -90,16 +99,6 @@ Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataTh
xaxis->setLabelFormat("%.0f");
xaxis->setTitleText("Time [ns]");
updateTraceThread = new TimingThread();
updateTraceThread->SetWaitTimeinSec(ScopeUpdateMiliSec / 1000.);
connect(updateTraceThread, &TimingThread::timeUp, this, &Scope::UpdateScope);
updateScalarThread = new TimingThread();
updateScalarThread->SetWaitTimeinSec(2);
connect(updateScalarThread, &TimingThread::timeUp, this, [=](){
emit UpdateScaler();
});
NullThePointers();
//*================================== UI
@ -216,7 +215,7 @@ Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataTh
QLabel * lbhints = new QLabel("Type 'r' to restore view, '+/-' Zoom in/out, arrow key to pan.", this);
layout->addWidget(lbhints, rowID, 0, 1, 4);
QLabel * lbinfo = new QLabel("Trace updates every " + QString::number(updateTraceThread->GetWaitTimeinSec()) + " sec.", this);
QLabel * lbinfo = new QLabel("Trace updates every " + QString::number(ScopeUpdateMiliSec / 1000.) + " sec.", this);
lbinfo->setAlignment(Qt::AlignRight);
layout->addWidget(lbinfo, rowID, 6);
@ -278,22 +277,32 @@ Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataTh
yaxis->setRange(0, 0xFFF);
}
workerThread = new QThread(this);
scopeWorker = new ScopeWorker(this);
scopeTimer = new QTimer(this);
scopeWorker->moveToThread(workerThread);
// Setup the timer to trigger every second
connect(scopeTimer, &QTimer::timeout, scopeWorker, [=](){
scopeWorker->UpdateScope();
});
workerThread->start();
enableSignalSlot = true;
}
Scope::~Scope(){
DebugPrint("%s", "Scope");
updateTraceThread->Stop();
updateTraceThread->quit();
updateTraceThread->wait();
delete updateTraceThread;
updateScalarThread->Stop();
updateScalarThread->quit();
updateScalarThread->wait();
delete updateScalarThread;
scopeTimer->stop();
// scalarTimer->stop();
if( workerThread->isRunning() ){
workerThread->quit();
workerThread->wait();
}
for( int i = 0; i < MaxNumberOfTrace; i++) delete dataTrace[i];
delete plot;
@ -422,8 +431,7 @@ void Scope::StartScope(){
}
updateTraceThread->start();
updateScalarThread->start();
scopeTimer->start(ScopeUpdateMiliSec);
bnScopeStart->setEnabled(false);
bnScopeStart->setStyleSheet("");
@ -434,7 +442,7 @@ void Scope::StartScope(){
EnableControl(false);
TellACQOnOff(true);
emit TellACQOnOff(true);
isACQStarted = true;
@ -445,13 +453,8 @@ void Scope::StopScope(){
if( !digi ) return;
// printf("------ Scope::%s \n", __func__);
updateTraceThread->Stop();
updateTraceThread->quit();
updateTraceThread->exit();
updateScalarThread->Stop();
updateScalarThread->quit();
updateScalarThread->exit();
scopeTimer->stop();
// scalarTimer->stop();
if( chkSoleRun->isChecked() ){
@ -467,7 +470,6 @@ void Scope::StopScope(){
digiMTX[ID].lock();
digi[ID]->StopACQ();
digi[ID]->ReadACQStatus();
digiMTX[ID].unlock();
//restore setting
@ -498,9 +500,9 @@ void Scope::StopScope(){
readDataThread[iDigi]->wait();
readDataThread[iDigi]->SetScopeMode(false);
}
digiMTX[iDigi].lock();
digi[iDigi]->StopACQ();
digi[iDigi]->ReadACQStatus();
//digi[iDigi]->GetData()->PrintAllData();
digiMTX[iDigi].unlock();
@ -511,6 +513,8 @@ void Scope::StopScope(){
}
runStatus->setStyleSheet(""); // cheated, don;t know why digi[iDigi]->GetACQStatusFromMemory(), sometimes return ACQ one.
emit UpdateOtherPanels();
bnScopeStart->setEnabled(true);
@ -523,7 +527,7 @@ void Scope::StopScope(){
EnableControl(true);
TellACQOnOff(false);
emit TellACQOnOff(false);
isACQStarted = false;
@ -736,7 +740,7 @@ void Scope::SetUpSpinBox(RSpinBox * &sb, QString str, int row, int col, const Re
value = uint16_t((1.0 - sb->value()/100.) * 0xFFFF);
}
if( para == DPP::PHA::TriggerThreshold ){
if( para == DPP::PHA::TriggerThreshold || para == DPP::PSD::TriggerThreshold){
value = sb->value();
}
@ -745,7 +749,7 @@ void Scope::SetUpSpinBox(RSpinBox * &sb, QString str, int row, int col, const Re
if( digi[ID]->GetDPPType() == DPPTypeCode::DPP_QDC_CODE ){
int grp = ch/8; // convert ch to grp
digiMTX[ID].lock();
digi[ID]->WriteRegister(para, value, grp);
digi[ID]->WriteRegister(para, value, grp);
digiMTX[ID].unlock();
}else{
digiMTX[ID].lock();
@ -1254,6 +1258,7 @@ void Scope::UpdatePanel_PSD(){
UpdateSpinBox(sbShortGate, DPP::PSD::ShortGateWidth);
UpdateSpinBox(sbLongGate, DPP::PSD::LongGateWidth);
UpdateSpinBox(sbGateOffset, DPP::PSD::GateOffset);
UpdateSpinBox(sbThreshold, DPP::PSD::TriggerThreshold);
uint32_t BdCfg = digi[ID]->GetSettingFromMemory(DPP::BoardConfiguration, ch);

27
Scope.h
View File

@ -12,6 +12,7 @@
#include <QComboBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QTimer>
#include <QLineSeries>
#include <QRubberBand>
#include <QMouseEvent>
@ -22,6 +23,8 @@
#include "CustomThreads.h"
#include "CustomWidgets.h"
class ScopeWorker; //Forward declaration
//^====================================================
//^====================================================
class Scope : public QMainWindow{
@ -51,7 +54,6 @@ signals:
void CloseWindow();
void SendLogMsg(const QString &msg);
void TellACQOnOff(const bool onOff);
void UpdateScaler();
void UpdateOtherPanels();
private:
@ -87,8 +89,6 @@ private:
unsigned short oldCh, oldDigi;
ReadDataThread ** readDataThread;
TimingThread * updateTraceThread;
TimingThread * updateScalarThread;
bool enableSignalSlot;
@ -147,8 +147,29 @@ private:
//sbGateOffset -> GateOffset
//sbTriggerHoldOff ->Trigger Hold Off
QThread * workerThread;
ScopeWorker * scopeWorker;
QTimer * scopeTimer;
};
//^#======================================================== ScopeWorker
class ScopeWorker : public QObject{
Q_OBJECT
public:
ScopeWorker(Scope * parent): SS(parent){}
public slots:
void UpdateScope(){
SS->UpdateScope();
emit workDone();
}
signals:
void workDone();
private:
Scope * SS;
};
#endif

View File

@ -4,12 +4,13 @@
#include <QGroupBox>
#include <QStandardItemModel>
#include <QLabel>
// #include <QScreen>
SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawDataPath, QMainWindow * parent) : QMainWindow(parent){
DebugPrint("%s", "SingleSpectra");
this->digi = digi;
this->nDigi = nDigi;
this->rawDataPath = rawDataPath;
this->settingPath = rawDataPath + "/HistogramSettings.txt";
maxFillTimeinMilliSec = 1000;
maxFillTimePerDigi = maxFillTimeinMilliSec/nDigi;
@ -17,8 +18,15 @@ SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawD
isSignalSlotActive = true;
setWindowTitle("Single Histograms");
setGeometry(0, 0, 1000, 800);
//setWindowFlags( this->windowFlags() & ~Qt::WindowCloseButtonHint );
//====== resize window if screen too small
QScreen * screen = QGuiApplication::primaryScreen();
QRect screenGeo = screen->geometry();
if( screenGeo.width() < 1000 || screenGeo.height() < 800) {
setGeometry(0, 0, screenGeo.width() - 100, screenGeo.height() - 100);
}else{
setGeometry(0, 0, 1000, 800);
}
QWidget * layoutWidget = new QWidget(this);
setCentralWidget(layoutWidget);
@ -73,101 +81,17 @@ SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawD
}
});
QPushButton * bnRebinDigi = new QPushButton("Rebin Energy", this);
ctrlLayout->addWidget(bnRebinDigi, 0, 6, 1, 2);
connect(bnRebinDigi, &QPushButton::clicked, this, [=](){
int ID = cbDigi->currentIndex();
int ch = cbCh->currentIndex();
int a_Bin;
float a_Min, a_Max;
if( ch >= 0 ){
a_Bin = hist[ID][ch]->GetNBin();
a_Min = hist[ID][ch]->GetXMin();
a_Max = hist[ID][ch]->GetXMax();
}else{
a_Bin = hist2D[ID]->GetYNBin();
a_Min = hist2D[ID]->GetYMin();
a_Max = hist2D[ID]->GetYMax();
}
//pop up a dialog for nBin and ranhe
QDialog dialog(this);
dialog.setWindowTitle("Rebin histograms");
QFormLayout layout(&dialog);
QLabel * info = new QLabel(&dialog);
info->setStyleSheet("color:red;");
info->setText("This will also clear histogram!!");
layout.addRow(info);
QStringList nameList = {"Num. Bin", "x-Min", "x-Max"};
QLineEdit* lineEdit[3];
for (int i = 0; i < 3; ++i) {
lineEdit[i] = new QLineEdit(&dialog);
layout.addRow(nameList[i] + " : ", lineEdit[i]);
}
lineEdit[0]->setText(QString::number(a_Bin));
lineEdit[1]->setText(QString::number(a_Min));
lineEdit[2]->setText(QString::number(a_Max));
QLabel * msg = new QLabel(&dialog);
msg->setStyleSheet("color:red;");
layout.addRow(msg);
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
layout.addRow(&buttonBox);
double number[3];
QObject::connect(&buttonBox, &QDialogButtonBox::accepted, [&]() {
int OKcount = 0;
bool conversionOk = true;
for( int i = 0; i < 3; i++ ){
number[i] = lineEdit[i]->text().toDouble(&conversionOk);
if( conversionOk ){
OKcount++;
}else{
msg->setText(nameList[i] + " is invalid.");
return;
}
}
if( OKcount == 3 ) {
if( number[2] > number[1] ) {
dialog.accept();
}else{
msg->setText(nameList[2] + " is smaller than " + nameList[1]);
}
}
});
QObject::connect(&buttonBox, &QDialogButtonBox::rejected, [&]() { dialog.reject();});
if( dialog.exec() == QDialog::Accepted ){
if( hist2D[ID] ) {
hist2D[ID]->RebinY((int)number[0], number[1], number[2]);
hist2D[ID]->rescaleAxes();
hist2D[ID]->UpdatePlot();
}
for( int j = 0; j < digi[ID]->GetNumInputCh(); j++){
if( hist[ID][j] ) {
hist[ID][j]->Rebin((int)number[0], number[1], number[2]);
hist[ID][j]->UpdatePlot();
}
}
}
});
QCheckBox * chkIsFillHistogram = new QCheckBox("Fill Histograms", this);
ctrlLayout->addWidget(chkIsFillHistogram, 0, 8);
connect(chkIsFillHistogram, &QCheckBox::stateChanged, this, [=](int state){ fillHistograms = state;});
chkIsFillHistogram = new QCheckBox("Fill Histograms", this);
ctrlLayout->addWidget(chkIsFillHistogram, 0, 6, 1, 2);
chkIsFillHistogram->setChecked(false);
fillHistograms = false;
isFillingHistograms = false;
QLabel * lbSettingPath = new QLabel( settingPath , this);
ctrlLayout->addWidget(lbSettingPath, 1, 0, 1, 6);
QPushButton * bnSaveButton = new QPushButton("Save Hist. Settings", this);
ctrlLayout->addWidget(bnSaveButton, 1, 6, 1, 2);
connect(bnSaveButton, &QPushButton::clicked, this, &SingleSpectra::SaveSetting);
}
@ -193,6 +117,9 @@ SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawD
for( int j = 0; j < digi[i]->GetNumInputCh(); j++){
if( i < nDigi ) {
hist[i][j] = new Histogram1D("Digi-" + QString::number(digi[i]->GetSerialNumber()) +", Ch-" + QString::number(j), "Raw Energy [ch]", nBin, eMin, eMax);
if( digi[i]->GetDPPType() == DPPTypeCode::DPP_PSD_CODE ){
hist[i][j]->AddDataList("Short Energy", Qt::green);
}
}else{
hist[i][j] = nullptr;
}
@ -216,10 +143,28 @@ SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawD
ClearInternalDataCount();
workerThread = new QThread(this);
histWorker = new HistWorker(this);
timer = new QTimer(this);
histWorker->moveToThread(workerThread);
// Setup the timer to trigger every second
connect(timer, &QTimer::timeout, histWorker, &HistWorker::FillHistograms);
workerThread->start();
}
SingleSpectra::~SingleSpectra(){
DebugPrint("%s", "SingleSpectra");
timer->stop();
if( workerThread->isRunning() ){
workerThread->quit();
workerThread->wait();
}
SaveSetting();
for( unsigned int i = 0; i < nDigi; i++ ){
@ -289,9 +234,13 @@ void SingleSpectra::ChangeHistView(){
}
void SingleSpectra::FillHistograms(){
// DebugPrint("%s", "SingleSpectra");
if( !fillHistograms ) return;
// printf("%s | %d %d \n", __func__, chkIsFillHistogram->checkState(), isFillingHistograms);
if( this->isVisible() == false ) return;
if( chkIsFillHistogram->checkState() == Qt::Unchecked ) return;
if( isFillingHistograms) return;
isFillingHistograms = true;
timespec t0, t1;
QVector<int> randomDigiList = generateNonRepeatedCombination(nDigi);
@ -304,17 +253,15 @@ void SingleSpectra::FillHistograms(){
QVector<int> randomChList = generateNonRepeatedCombination(digi[ID]->GetNumInputCh());
// qDebug() << randomChList;
digiMTX[ID].lock();
// digiMTX[ID].lock();
// digi[ID]->GetData()->PrintAllData();
clock_gettime(CLOCK_REALTIME, &t0);
for( int k = 0; k < digi[ID]->GetNumInputCh(); k ++ ){
int ch = randomChList[k];
int lastIndex = digi[ID]->GetData()->GetDataIndex(ch);
// printf("--- ch %2d | last index %d \n", ch, lastIndex);
if( lastIndex < 0 ) continue;
// printf("--- ch %2d | last index %d \n", ch, lastIndex);
int loopIndex = digi[ID]->GetData()->GetLoopIndex(ch);
@ -345,6 +292,11 @@ void SingleSpectra::FillHistograms(){
// printf(" ch: %d, last fill idx : %d | %d \n", ch, lastFilledIndex[ID][ch], data);
hist[ID][ch]->Fill( data );
if( digi[i]->GetDPPType() == DPPTypeCode::DPP_PSD_CODE ){
uShort e2 = digi[ID]->GetData()->GetEnergy2(ch, lastFilledIndex[ID][ch]);
// printf("%u \n", e2);
hist[ID][ch]->Fill( e2, 1);
}
hist2D[ID]->Fill(ch, data);
}
if( histVisibility[ID][ch] ) hist[ID][ch]->UpdatePlot();
@ -354,44 +306,65 @@ void SingleSpectra::FillHistograms(){
}
if( hist2DVisibility[ID] ) hist2D[ID]->UpdatePlot();
digiMTX[ID].unlock();
// digiMTX[ID].unlock();
}
isFillingHistograms = false;
}
void SingleSpectra::SaveSetting(){
DebugPrint("%s", "SingleSpectra");
QFile file(rawDataPath + "/singleSpectraSetting.txt");
file.open(QIODevice::Text | QIODevice::WriteOnly);
QFile file(settingPath );
for( unsigned int i = 0; i < nDigi; i++){
file.write(("======= " + QString::number(digi[i]->GetSerialNumber()) + "\n").toStdString().c_str());
for( int ch = 0; ch < digi[i]->GetNumInputCh() ; ch++){
QString a = QString::number(ch).rightJustified(2, ' ');
QString b = QString::number(hist[i][ch]->GetNBin()).rightJustified(6, ' ');
QString c = QString::number(hist[i][ch]->GetXMin()).rightJustified(6, ' ');
QString d = QString::number(hist[i][ch]->GetXMax()).rightJustified(6, ' ');
file.write( QString("%1 %2 %3 %4\n").arg(a).arg(b).arg(c).arg(d).toStdString().c_str() );
if (!file.exists()) {
// If the file does not exist, create it
if (!file.open(QIODevice::WriteOnly)) {
qWarning() << "Could not create file" << settingPath;
} else {
qDebug() << "File" << settingPath << "created successfully";
file.close();
}
QString a = QString::number(digi[i]->GetNumInputCh()).rightJustified(2, ' ');
QString b = QString::number(hist2D[i]->GetXNBin()).rightJustified(6, ' ');
QString c = QString::number(hist2D[i]->GetXMin()).rightJustified(6, ' ');
QString d = QString::number(hist2D[i]->GetXMax()).rightJustified(6, ' ');
QString e = QString::number(hist2D[i]->GetYNBin()).rightJustified(6, ' ');
QString f = QString::number(hist2D[i]->GetYMin()).rightJustified(6, ' ');
QString g = QString::number(hist2D[i]->GetYMax()).rightJustified(6, ' ');
file.write( QString("%1 %2 %3 %4 %5 %6 %7\n").arg(a).arg(b).arg(c).arg(d).arg(e).arg(f).arg(g).toStdString().c_str() );
}
file.write("//========== End of file\n");
file.close();
if( file.open(QIODevice::Text | QIODevice::WriteOnly) ){
for( unsigned int i = 0; i < nDigi; i++){
file.write(("======= " + QString::number(digi[i]->GetSerialNumber()) + "\n").toStdString().c_str());
for( int ch = 0; ch < digi[i]->GetNumInputCh() ; ch++){
QString a = QString::number(ch).rightJustified(2, ' ');
QString b = QString::number(hist[i][ch]->GetNBin()).rightJustified(6, ' ');
QString c = QString::number(hist[i][ch]->GetXMin()).rightJustified(6, ' ');
QString d = QString::number(hist[i][ch]->GetXMax()).rightJustified(6, ' ');
file.write( QString("%1 %2 %3 %4\n").arg(a).arg(b).arg(c).arg(d).toStdString().c_str() );
}
QString a = QString::number(digi[i]->GetNumInputCh()).rightJustified(2, ' ');
QString b = QString::number(hist2D[i]->GetXNBin()-2).rightJustified(6, ' ');
QString c = QString::number(hist2D[i]->GetXMin()).rightJustified(6, ' ');
QString d = QString::number(hist2D[i]->GetXMax()).rightJustified(6, ' ');
QString e = QString::number(hist2D[i]->GetYNBin()-2).rightJustified(6, ' ');
QString f = QString::number(hist2D[i]->GetYMin()).rightJustified(6, ' ');
QString g = QString::number(hist2D[i]->GetYMax()).rightJustified(6, ' ');
file.write( QString("%1 %2 %3 %4 %5 %6 %7\n").arg(a).arg(b).arg(c).arg(d).arg(e).arg(f).arg(g).toStdString().c_str() );
}
file.write("##========== End of file\n");
file.close();
printf("Saved Histogram Settings to %s\n", settingPath.toStdString().c_str());
}else{
printf("%s|cannot open HistogramSettings.txt\n", __func__);
}
}
void SingleSpectra::LoadSetting(){
DebugPrint("%s", "SingleSpectra");
QFile file(rawDataPath + "/singleSpectraSetting.txt");
QFile file(settingPath);
if( file.open(QIODevice::Text | QIODevice::ReadOnly) ){
@ -402,7 +375,7 @@ void SingleSpectra::LoadSetting(){
int digiID = -1;
while ( !line.isNull() ){
if( line.contains("//========== ") ) break;
if( line.contains("##========== ") ) break;
if( line.contains("//") ) continue;
if( line.contains("======= ") ){
digiSN = line.mid(7).toInt();
@ -422,21 +395,21 @@ void SingleSpectra::LoadSetting(){
QStringList list = line.split(QRegularExpression("\\s+"));
list.removeAll("");
if( list.count() != 4 ) {
line = in.readLine();
continue;
}
QVector<int> data;
// if( list.count() != 4 ) {
// line = in.readLine();
// continue;
// }
QVector<float> data;
for( int i = 0; i < list.count(); i++){
data.push_back(list[i].toInt());
data.push_back(list[i].toFloat());
}
if( 0 <= data[0] && data[0] < digi[digiID]->GetNumInputCh() ){
hist[digiID][data[0]]->Rebin(data[1], data[2], data[3]);
hist[digiID][int(data[0])]->Rebin(data[1], data[2], data[3]);
}
if( data[0] == digi[digiID]->GetNumInputCh() && data.size() == 7 ){
hist2D[digiID]->Rebin(data[1], data[2], data[3], data[4], data[5], data[6]);
if( int(data[0]) == digi[digiID]->GetNumInputCh() && data.size() == 7 ){
hist2D[digiID]->Rebin(int(data[1]), data[2], data[3], int(data[4]), data[5], data[6]);
}
}
@ -446,6 +419,8 @@ void SingleSpectra::LoadSetting(){
}else{
printf("%s|cannot open HistogramSettings.txt\n", __func__);
}
}

View File

@ -20,6 +20,7 @@
#include "Histogram1D.h"
#include "Histogram2D.h"
class HistWorker; //Forward decalration
//^====================================================
//^====================================================
@ -31,8 +32,8 @@ public:
~SingleSpectra();
void ClearInternalDataCount();
void SetFillHistograms(bool onOff) { fillHistograms = onOff;}
bool IsFillHistograms() const {return fillHistograms;}
// void SetFillHistograms(bool onOff) { fillHistograms = onOff;}
// bool IsFillHistograms() const {return fillHistograms;}
void LoadSetting();
void SaveSetting();
@ -45,17 +46,33 @@ public:
public slots:
void FillHistograms();
void ChangeHistView();
void startTimer(){
// printf("timer start\n");
timer->start(maxFillTimeinMilliSec);
}
void stopTimer(){
// printf("timer stop\n");
timer->stop();
ClearInternalDataCount();
}
private:
Digitizer ** digi;
unsigned short nDigi;
int lastFilledIndex[MaxNDigitizer][MaxNChannels];
int loopFilledIndex[MaxNDigitizer][MaxNChannels];
bool histVisibility[MaxNDigitizer][MaxNChannels];
bool hist2DVisibility[MaxNDigitizer];
unsigned short maxFillTimePerDigi;
bool isFillingHistograms;
Histogram1D * hist[MaxNDigitizer][MaxNChannels];
Histogram2D * hist2D[MaxNDigitizer];
bool histVisibility[MaxNDigitizer][MaxNChannels];
bool hist2DVisibility[MaxNDigitizer];
QCheckBox * chkIsFillHistogram;
RComboBox * cbDivision;
@ -66,17 +83,35 @@ private:
QGridLayout * histLayout;
int oldBd, oldCh;
int lastFilledIndex[MaxNDigitizer][MaxNChannels];
int loopFilledIndex[MaxNDigitizer][MaxNChannels];
bool fillHistograms;
QString rawDataPath;
QString settingPath;
unsigned short maxFillTimeinMilliSec;
unsigned short maxFillTimePerDigi;
bool isSignalSlotActive;
QThread * workerThread;
HistWorker * histWorker;
QTimer * timer;
};
//^#======================================================== HistWorker
class HistWorker : public QObject{
Q_OBJECT
public:
HistWorker(SingleSpectra * parent): SS(parent){}
public slots:
void FillHistograms(){
SS->FillHistograms();
emit workDone();
}
signals:
void workDone();
private:
SingleSpectra * SS;
};
#endif

View File

@ -13,7 +13,9 @@ Analyzer::Analyzer(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent )
setGeometry(0, 0, 1000, 800);
influx = nullptr;
dataBaseIP = "";
dataBaseName = "";
dataBaseToken = "";
dataList = new Data*[nDigi];
typeList.clear();
@ -28,9 +30,9 @@ Analyzer::Analyzer(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent )
isBuildBackward = false;
mb = new MultiBuilder(dataList, typeList, snList);
buildTimerThread = new TimingThread(this);
buildTimerThread->SetWaitTimeinSec(1.0); //^Set event build interval
connect( buildTimerThread, &TimingThread::timeUp, this, &Analyzer::UpdateHistograms);
// buildTimerThread = new TimingThread(this);
// buildTimerThread->SetWaitTimeinSec(1.0); //^Set event build interval
// connect( buildTimerThread, &TimingThread::timeUp, this, &Analyzer::UpdateHistograms);
QWidget * layoutWidget = new QWidget(this);
setCentralWidget(layoutWidget);
@ -40,9 +42,41 @@ Analyzer::Analyzer(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent )
// QPushButton * bnSetting = new QPushButton("Settings", this);
// layout->addWidget(bnSetting);
anaThread = new QThread(this);
anaWorker = new AnalyzerWorker(this);
anaTimer = new QTimer();
isWorking = false;
anaWorker->moveToThread(anaThread);
connect(anaTimer, &QTimer::timeout, anaWorker, [=](){
if( isWorking ) return;
isWorking = true;
anaWorker->UpdateHistograms();
isWorking = false;
});
// connect(anaWorker, &AnalyzerWorker::workDone, this, [=](){
// printf(" --------- work Done\n");
// });
anaThread->start();
}
Analyzer::~Analyzer(){
printf("Analyzer::%s\n", __func__);
anaTimer->stop();
printf(" is anaThread is running %d \n", anaThread->isRunning());
if( anaThread->isRunning() ){
anaThread->quit();
anaThread->wait();
}
printf("------ end of anaThread \n");
delete influx;
delete mb;
delete [] dataList;
@ -60,6 +94,62 @@ double Analyzer::RandomGauss(double mean, double sigma){
}
void Analyzer::SetDatabase(QString IP, QString Name, QString Token){
dataBaseIP = IP;
dataBaseName = Name;
dataBaseToken = Token;
if( influx ) {
delete influx;
influx = nullptr;
}
influx = new InfluxDB(dataBaseIP.toStdString());
if( influx->TestingConnection() ){
printf("InfluxDB URL (%s) is Valid. Version : %s\n", dataBaseIP.toStdString().c_str(), influx->GetVersionString().c_str());
if( influx->GetVersionNo() > 1 && dataBaseToken.isEmpty() ) {
printf("A Token is required for accessing the database.\n");
delete influx;
influx = nullptr;
return;
}
influx->SetToken(dataBaseToken.toStdString());
//==== chck database exist
influx->CheckDatabases();
std::vector<std::string> databaseList = influx->GetDatabaseList();
bool foundDatabase = false;
for( int i = 0; i < (int) databaseList.size(); i++){
if( databaseList[i] == dataBaseName.toStdString() ) foundDatabase = true;
// printf("%d | %s\n", i, databaseList[i].c_str());
}
if( foundDatabase ){
influx->AddDataPoint("test value=1");
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
if( influx->IsWriteOK() ){
printf("test write database OK.\n");
}else{
printf("################# test write database FAIL.\n");
delete influx;
influx = nullptr;
}
}else{
printf("Database name : %s NOT found.\n", dataBaseName.toStdString().c_str());
delete influx;
influx = nullptr;
}
}else{
printf("InfluxDB URL (%s) is NOT Valid. \n", dataBaseIP.toStdString().c_str());
delete influx;
influx = nullptr;
}
}
void Analyzer::RedefineEventBuilder(std::vector<int> idList){
delete mb;
delete [] dataList;
@ -76,31 +166,70 @@ void Analyzer::RedefineEventBuilder(std::vector<int> idList){
mb = new MultiBuilder(dataList, typeList, snList);
}
void Analyzer::StartThread(){
mb->ClearEvents();
buildTimerThread->start();
}
void Analyzer::StopThread(){
// printf("%s\n", __func__);
buildTimerThread->Stop();
buildTimerThread->quit();
buildTimerThread->wait();
}
void Analyzer::BuildEvents(bool verbose){
unsigned int nData = mb->GetNumOfDigitizer();
std::vector<int> idList = mb->GetDigiIDList();
for( unsigned int i = 0; i < nData; i++ ) digiMTX[idList[i]].lock();
// unsigned int nData = mb->GetNumOfDigitizer();
// std::vector<int> idList = mb->GetDigiIDList();
// for( unsigned int i = 0; i < nData; i++ ) digiMTX[idList[i]].lock();
if( isBuildBackward ){
mb->BuildEventsBackWard(maxNumEventBuilt, verbose);
}else{
mb->BuildEvents(0, 0, verbose);
mb->BuildEvents(0, true, verbose);
}
// mb->PrintStat();
// for( unsigned int i = 0; i < nData; i++ ) digiMTX[idList[i]].unlock();
}
void Analyzer::SetDatabaseButton(){
QDialog dialog;
dialog.setWindowTitle("Influx Database");
QGridLayout layout(&dialog);
//------------------------------
QLabel ipLabel("Database IP : ");
layout.addWidget(&ipLabel, 0, 0);
QLineEdit ipLineEdit;
ipLineEdit.setFixedSize(1000, 20);
ipLineEdit.setText(dataBaseIP);
layout.addWidget(&ipLineEdit, 0, 1);
//------------------------------
QLabel nameLabel("Database Name : ");
layout.addWidget(&nameLabel, 1, 0);
QLineEdit nameLineEdit;
nameLineEdit.setFixedSize(1000, 20);
nameLineEdit.setText(dataBaseName);
layout.addWidget(&nameLineEdit, 1, 1);
//------------------------------
QLabel tokenLabel("Database Token : ");
layout.addWidget(&tokenLabel, 2, 0);
QLineEdit tokenLineEdit;
tokenLineEdit.setFixedSize(1000, 20);
tokenLineEdit.setText(dataBaseToken);
layout.addWidget(&tokenLineEdit, 2, 1);
layout.addWidget(new QLabel("Only for version 2+, version 1+ can be skipped."), 3, 0, 1, 2);
// Buttons for OK and Cancel
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
layout.addWidget(&buttonBox);
QObject::connect(&buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
QObject::connect(&buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
dialog.resize(400, dialog.sizeHint().height()); // Set the width to 400 pixels
// Show the dialog and get the result
if (dialog.exec() == QDialog::Accepted) {
SetDatabase(ipLineEdit.text().trimmed(), nameLineEdit.text().trimmed(),tokenLineEdit.text().trimmed());
}
for( unsigned int i = 0; i < nData; i++ ) digiMTX[idList[i]].unlock();
}

View File

@ -29,10 +29,17 @@ This is the mother of all other derivative analysis class.
derivative class should define the SetUpCanvas() and UpdateHistogram();
After creating a new class based on the Analyzer class,
users need to add the class files to the FSUDAQ_Qt6.pro project file,
include the header file in FSUDAQ.cpp,
modify the MainWindow::OpenAnalyzer() method,
and recompile FSUDAQ to incorporate the changes and activate the custom analyzer.
***************************************/
#include "Histogram1D.h"
#include "Histogram2D.h"
class AnalyzerWorker; //Forward decalration
//^==============================================
//^==============================================
@ -43,32 +50,47 @@ public:
Analyzer(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent = nullptr);
virtual ~Analyzer();
virtual void SetUpCanvas();
MultiBuilder * GetEventBuilder() { return mb;}
void RedefineEventBuilder(std::vector<int> idList);
void SetBackwardBuild(bool TF, int maxNumEvent = 100) { isBuildBackward = TF; maxNumEventBuilt = maxNumEvent;}
void SetDatabase(QString IP, QString Name, QString Token);
double RandomGauss(double mean, double sigma);
void SetDatabaseButton();
public slots:
void StartThread();
void StopThread();
double GetUpdateTimeInSec() const {return waitTimeinSec;}
virtual void SetUpCanvas();
virtual void UpdateHistograms(); // where event-building, analysis, and ploting
private slots:
public slots:
void startTimer(){
// printf("start timer\n");
mb->ForceStop(false);
mb->ClearEvents();
anaTimer->start(waitTimeinSec*1000);
}
void stopTimer(){
// printf("stop worker\n");
anaTimer->stop();
mb->ForceStop(true);
}
private slots:
protected:
QGridLayout * layout;
void BuildEvents(bool verbose = false);
void SetUpdateTimeInSec(double sec = 1.0) {waitTimeinSec = sec; buildTimerThread->SetWaitTimeinSec(waitTimeinSec);}
void SetUpdateTimeInSec(double sec = 1.0) { waitTimeinSec = sec; }
InfluxDB * influx;
std::string dataBaseName;
QString dataBaseIP;
QString dataBaseName;
QString dataBaseToken;
bool isWorking; // a flag to indicate the worker is working
private:
Digitizer ** digi;
unsigned short nDigi;
@ -81,8 +103,32 @@ private:
MultiBuilder * mb;
bool isBuildBackward;
int maxNumEventBuilt;
TimingThread * buildTimerThread;
// TimingThread * buildTimerThread;
QThread * anaThread;
AnalyzerWorker * anaWorker;
QTimer * anaTimer;
};
//^================================================ AnalyzerWorker
class AnalyzerWorker : public QObject{
Q_OBJECT
public:
AnalyzerWorker(Analyzer * parent): SS(parent){}
public slots:
void UpdateHistograms(){
SS->UpdateHistograms();
emit workDone();
}
signals:
void workDone();
private:
Analyzer * SS;
};
#endif

View File

@ -33,7 +33,7 @@ public:
evtbder->SetTimeWindow(500);
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
influx = new InfluxDB("https://localhost:8086");
dataBaseName = "testing";
SetUpCanvas(); // see below
@ -85,7 +85,7 @@ inline void BeamTune::SetUpCanvas(){
layout->addWidget(hFrame, 0, 0, 1, 2);
hFrame1 = new Histogram2D("X Map", "X-axis", "Y-axis", 100, -10, 110, 100, -0.8, 0.8, this);
layout->addWidget(hFrame1, 1, 1, 1, 2);
layout->addWidget(hFrame1, 1, 0, 1, 2);
/*
@ -137,38 +137,38 @@ inline void BeamTune::UpdateHistograms(){
if( event.size() == 0 ) return;
e0 = 0;
e1 = 0;
e2 = 0;
e3 = 0;
e0 = 0;
e1 = 0;
e2 = 0;
e3 = 0;
t0 = 0;
t1 = 0;
t2 = 0;
t3 = 0;
t0 = 0;
t1 = 0;
t2 = 0;
t3 = 0;
s0 = 0;
s1 = 0;
s2 = 0;
s3 = 0;
s0 = 0;
s1 = 0;
s2 = 0;
s3 = 0;
s_t0 = 0;
s_t1 = 0;
s_t2 = 0;
s_t3 = 0;
s_t0 = 0;
s_t1 = 0;
s_t2 = 0;
s_t3 = 0;
//std::vector<TLine*> lines; // Store lines to draw after the loop
//std::vector<TMarker*> markers; // Store markers to draw after the loop
//int lineCount = 0; // Counter to keep track of the number of lines
//std::vector<TLine*> lines; // Store lines to draw after the loop
//std::vector<TMarker*> markers; // Store markers to draw after the loop
//int lineCount = 0; // Counter to keep track of the number of lines
for( int k = 0; k < (int) event.size(); k++ ){
//event[k].Print();
if( event[k].ch == 2 ) {s0 = event[k].energy; s_t0 = event[k].timestamp;} //
if( event[k].ch == 3 ) {s1= event[k].energy; s_t1 = event[k].timestamp;} // The 4 output signals from the
if( event[k].ch == 3 ) {s1 = event[k].energy; s_t1 = event[k].timestamp;} // The 4 output signals from the
if( event[k].ch == 4 ) {s2 = event[k].energy; s_t2 = event[k].timestamp;} // MCP detector
if( event[k].ch == 5 ) {s3= event[k].energy; s_t3 = event[k].timestamp;} //
if( event[k].ch == 5 ) {s3 = event[k].energy; s_t3 = event[k].timestamp;} //
if( event[k].ch == 10 ) {e0 = event[k].energy; t0 = event[k].timestamp;} //
if( event[k].ch == 11 ) {e1= event[k].energy; t1 = event[k].timestamp;} // The 4 output signals from the
@ -178,8 +178,8 @@ inline void BeamTune::UpdateHistograms(){
}
if (s0>10 && s1>10 && s2>10 && s3>10 && e0>10 && e1>10 && e2>10 && e3>10) {
float_t rotation_angle = 31.;
double_t Xr = (((s1+s2)/(s0+s1+s2+s3))-0.51)*cos(-rotation_angle*M_PI/180)-(((s2+s3)/(s0+s1+s2+s3))-0.51)*sin(-rotation_angle*M_PI/180);
float_t rotation_angle = 31.;
double_t Xr = (((s1+s2)/(s0+s1+s2+s3))-0.51)*cos(-rotation_angle*M_PI/180)-(((s2+s3)/(s0+s1+s2+s3))-0.51)*sin(-rotation_angle*M_PI/180);
double_t Yr = (((s1+s2)/(s0+s1+s2+s3))-0.51)*sin(-rotation_angle*M_PI/180)+(((s2+s3)/(s0+s1+s2+s3))-0.51)*cos(-rotation_angle*M_PI/180);
double_t X2 = ((e0-e1)/(e0+e1)); // PSD X position

View File

@ -2,37 +2,29 @@
#define COINCIDENTANLAYZER_H
#include "Analyser.h"
#include "FSUDAQ.h"
//^===========================================
class CoincidentAnalyzer : public Analyzer{
Q_OBJECT
public:
CoincidentAnalyzer(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent = nullptr): Analyzer(digi, nDigi, parent){
CoincidentAnalyzer(Digitizer ** digi, unsigned int nDigi, QString rawDataPath, QMainWindow * parent = nullptr): Analyzer(digi, nDigi, parent){
this->digi = digi;
this->nDigi = nDigi;
this->rawDataPath = rawDataPath;
SetUpdateTimeInSec(1.0);
//RedefineEventBuilder({0}); // only build for the 0-th digitizer, otherwise, it will build event accross all digitizers
SetBackwardBuild(false, 100); // using normal building (acceding in time) or backward building, int the case of backward building, default events to be build is 100.
evtbder = GetEventBuilder();
evtbder->SetTimeWindow(500);
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
dataBaseName = "testing";
mb->SetTimeWindow(500);
allowSignalSlot = false;
SetUpCanvas();
LoadHistRange();
}
~CoincidentAnalyzer(){
SaveHistRange();
}
void SetUpCanvas();
@ -42,13 +34,11 @@ public slots:
private:
Digitizer ** digi;
unsigned int nDigi;
MultiBuilder *evtbder;
bool allowSignalSlot;
QLineEdit * leInfluxIP;
QLineEdit * leDBName;
// declaie histograms
Histogram2D * h2D;
Histogram1D * h1;
@ -73,35 +63,48 @@ private:
RComboBox * aDigi;
RComboBox * aCh;
void SaveHistRange();
void LoadHistRange();
QString rawDataPath;
void SaveSettings();
void LoadSettings();
};
inline void CoincidentAnalyzer::SetUpCanvas(){
setWindowTitle("Online Coincident Analyzer");
setGeometry(0, 0, 1600, 1000);
{//^====== magnet and reaction setting
{//^====== channel settings
QGroupBox * box = new QGroupBox("Configuration", this);
layout->addWidget(box, 0, 0);
QGridLayout * boxLayout = new QGridLayout(box);
boxLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
box->setLayout(boxLayout);
int rowID = 0;
{
chkRunAnalyzer = new QCheckBox("Run Analyzer", this);
boxLayout->addWidget(chkRunAnalyzer, 0, 0);
boxLayout->addWidget(chkRunAnalyzer, rowID, 0);
connect(chkRunAnalyzer, &QCheckBox::stateChanged, this, [=](int state){
sbBuildWindow->setEnabled(state != Qt::Checked);
sbUpdateTime->setEnabled(state != Qt::Checked);
chkBackWardBuilding->setEnabled(state != Qt::Checked);
sbBackwardCount->setEnabled(state != Qt::Checked);
});
QLabel * lbUpdateTime = new QLabel("Update Period [s]", this);
lbUpdateTime->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbUpdateTime, 0, 1);
boxLayout->addWidget(lbUpdateTime, rowID, 1);
sbUpdateTime = new RSpinBox(this, 1);
sbUpdateTime->setMinimum(0.1);
sbUpdateTime->setMaximum(5);
sbUpdateTime->setValue(1);
boxLayout->addWidget(sbUpdateTime, 0, 2);
boxLayout->addWidget(sbUpdateTime, rowID, 2);
connect(sbUpdateTime, &RSpinBox::valueChanged, this, [=](){ sbUpdateTime->setStyleSheet("color : blue"); });
@ -110,17 +113,36 @@ inline void CoincidentAnalyzer::SetUpCanvas(){
SetUpdateTimeInSec(sbUpdateTime->value());
});
QLabel * lbBuildWindow = new QLabel("Event Window [ns]", this);
lbBuildWindow->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbBuildWindow, rowID, 3);
sbBuildWindow = new RSpinBox(this, 0);
sbBuildWindow->setMinimum(1);
sbBuildWindow->setMaximum(9999999999);
sbBuildWindow->setValue(1000);
boxLayout->addWidget(sbBuildWindow, rowID, 4);
connect(sbBuildWindow, &RSpinBox::valueChanged, this, [=](){
sbBuildWindow->setStyleSheet("color : blue;");
});
connect(sbBuildWindow, &RSpinBox::returnPressed, this, [=](){
sbBuildWindow->setStyleSheet("");
mb->SetTimeWindow((int)sbBuildWindow->value());
});
rowID ++;
chkBackWardBuilding = new QCheckBox("Use Backward builder", this);
boxLayout->addWidget(chkBackWardBuilding, 1, 0);
boxLayout->addWidget(chkBackWardBuilding, rowID, 0);
QLabel * lbBKWindow = new QLabel("Max No. Backward Event", this);
lbBKWindow->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbBKWindow, 1, 1);
boxLayout->addWidget(lbBKWindow, rowID, 1);
sbBackwardCount = new RSpinBox(this, 0);
sbBackwardCount->setMinimum(1);
sbBackwardCount->setMaximum(9999);
sbBackwardCount->setValue(100);
boxLayout->addWidget(sbBackwardCount, 1, 2);
boxLayout->addWidget(sbBackwardCount, rowID, 2);
chkBackWardBuilding->setChecked(false);
sbBackwardCount->setEnabled(false);
@ -140,61 +162,48 @@ inline void CoincidentAnalyzer::SetUpCanvas(){
SetBackwardBuild(true, sbBackwardCount->value());
});
QLabel * lbBuildWindow = new QLabel("Event Window [tick]", this);
lbBuildWindow->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbBuildWindow, 2, 1);
sbBuildWindow = new RSpinBox(this, 0);
sbBuildWindow->setMinimum(1);
sbBuildWindow->setMaximum(9999999999);
boxLayout->addWidget(sbBuildWindow, 2, 2);
connect(sbBuildWindow, &RSpinBox::valueChanged, this, [=](){
sbBuildWindow->setStyleSheet("color : blue;");
});
connect(sbBuildWindow, &RSpinBox::returnPressed, this, [=](){
sbBuildWindow->setStyleSheet("");
evtbder->SetTimeWindow((int)sbBuildWindow->value());
});
}
{
QFrame *separator = new QFrame(box);
separator->setFrameShape(QFrame::HLine);
separator->setFrameShadow(QFrame::Sunken);
boxLayout->addWidget(separator, 3, 0, 1, 4);
rowID ++;
QFrame *separator0 = new QFrame(box);
separator0->setFrameShape(QFrame::HLine);
separator0->setFrameShadow(QFrame::Sunken);
boxLayout->addWidget(separator0, rowID, 0, 1, 4);
rowID ++;
QLabel * lbXDigi = new QLabel("X-Digi", this);
lbXDigi->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbXDigi, 4, 0);
boxLayout->addWidget(lbXDigi, rowID, 0);
xDigi = new RComboBox(this);
for(unsigned int i = 0; i < nDigi; i ++ ){
xDigi->addItem("Digi-" + QString::number(digi[i]->GetSerialNumber()), i);
}
boxLayout->addWidget(xDigi, 4, 1);
boxLayout->addWidget(xDigi, rowID, 1);
QLabel * lbXCh = new QLabel("X-Ch", this);
lbXCh->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbXCh, 4, 2);
boxLayout->addWidget(lbXCh, rowID, 2);
xCh = new RComboBox(this);
for( int i = 0; i < digi[0]->GetNumInputCh(); i++) xCh->addItem("Ch-" + QString::number(i), i);
boxLayout->addWidget(xCh, 4, 3);
boxLayout->addWidget(xCh, rowID, 3);
rowID ++;
QLabel * lbYDigi = new QLabel("Y-Digi", this);
lbYDigi->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbYDigi, 5, 0);
boxLayout->addWidget(lbYDigi, rowID, 0);
yDigi = new RComboBox(this);
for(unsigned int i = 0; i < nDigi; i ++ ){
yDigi->addItem("Digi-" + QString::number(digi[i]->GetSerialNumber()), i);
}
boxLayout->addWidget(yDigi, 5, 1);
boxLayout->addWidget(yDigi, rowID, 1);
QLabel * lbYCh = new QLabel("Y-Ch", this);
lbYCh->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbYCh, 5, 2);
boxLayout->addWidget(lbYCh, rowID, 2);
yCh = new RComboBox(this);
for( int i = 0; i < digi[0]->GetNumInputCh(); i++) yCh->addItem("Ch-" + QString::number(i), i);
boxLayout->addWidget(yCh, 5, 3);
boxLayout->addWidget(yCh, rowID, 3);
connect(xDigi, &RComboBox::currentIndexChanged, this, [=](){
allowSignalSlot = false;
@ -241,26 +250,28 @@ inline void CoincidentAnalyzer::SetUpCanvas(){
}
{
rowID ++;
QFrame *separator1 = new QFrame(box);
separator1->setFrameShape(QFrame::HLine);
separator1->setFrameShadow(QFrame::Sunken);
boxLayout->addWidget(separator1, 6, 0, 1, 4);
boxLayout->addWidget(separator1, rowID, 0, 1, 4);
rowID ++;
QLabel * lbaDigi = new QLabel("ID-Digi", this);
lbaDigi->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbaDigi, 7, 0);
boxLayout->addWidget(lbaDigi, rowID, 0);
aDigi = new RComboBox(this);
for(unsigned int i = 0; i < nDigi; i ++ ){
aDigi->addItem("Digi-" + QString::number(digi[i]->GetSerialNumber()), digi[i]->GetSerialNumber());
aDigi->addItem("Digi-" + QString::number(digi[i]->GetSerialNumber()), i);
}
boxLayout->addWidget(aDigi, 7, 1);
boxLayout->addWidget(aDigi, rowID, 1);
QLabel * lbaCh = new QLabel("1D-Ch", this);
lbaCh->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbaCh, 7, 2);
boxLayout->addWidget(lbaCh, rowID, 2);
aCh = new RComboBox(this);
for( int i = 0; i < digi[0]->GetNumInputCh(); i++) aCh->addItem("Ch-" + QString::number(i), i);
boxLayout->addWidget(aCh, 7, 3);
boxLayout->addWidget(aCh, rowID, 3);
connect(aDigi, &RComboBox::currentIndexChanged, this, [=](){
allowSignalSlot = false;
@ -290,13 +301,47 @@ inline void CoincidentAnalyzer::SetUpCanvas(){
}
{
QFrame *separator1 = new QFrame(box);
separator1->setFrameShape(QFrame::HLine);
separator1->setFrameShadow(QFrame::Sunken);
boxLayout->addWidget(separator1, 8, 0, 1, 4);
rowID ++;
QFrame *separator2 = new QFrame(box);
separator2->setFrameShape(QFrame::HLine);
separator2->setFrameShadow(QFrame::Sunken);
boxLayout->addWidget(separator2, rowID, 0, 1, 4);
QPushButton * bnClearHist = new QPushButton("Clear All Hist.");
boxLayout->addWidget(bnClearHist, 9, 1);
rowID ++;
QLabel * lbIP = new QLabel("Database IP :", box);
lbIP->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbIP, rowID, 0);
leInfluxIP = new QLineEdit(box);
leInfluxIP->setReadOnly(true);
boxLayout->addWidget(leInfluxIP, rowID, 1, 1, 3);
QPushButton * bnInflux = new QPushButton("Set Influx", box);
boxLayout->addWidget(bnInflux, rowID, 4);
rowID ++;
QLabel * lbDBName = new QLabel("Database name :", box);
lbDBName->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbDBName, rowID, 0);
leDBName = new QLineEdit(box);
leDBName->setReadOnly(true);
boxLayout->addWidget(leDBName, rowID, 1);
connect(bnInflux, &QPushButton::clicked, this, [=](){
SetDatabaseButton();
if( influx ) {
leDBName->setText(dataBaseName);
leInfluxIP->setText(dataBaseIP);
}
});
// rowID ++;
// QFrame *separator3 = new QFrame(box);
// separator3->setFrameShape(QFrame::HLine);
// separator3->setFrameShadow(QFrame::Sunken);
// boxLayout->addWidget(separator3, rowID, 0, 1, 4);
QPushButton * bnClearHist = new QPushButton("Clear All Hist.", this);
boxLayout->addWidget(bnClearHist, rowID, 2);
connect(bnClearHist, &QPushButton::clicked, this, [=](){
h2D->Clear();
@ -305,17 +350,26 @@ inline void CoincidentAnalyzer::SetUpCanvas(){
hMulti->Clear();
});
}
QPushButton * bnSaveSettings = new QPushButton("Save Settings", this);
boxLayout->addWidget(bnSaveSettings, rowID, 3);
connect(bnSaveSettings, &QPushButton::clicked, this, &CoincidentAnalyzer::SaveSettings);
QPushButton * bnLoadSettings = new QPushButton("Load Settings", this);
boxLayout->addWidget(bnLoadSettings, rowID, 4);
connect(bnLoadSettings, &QPushButton::clicked, this, &CoincidentAnalyzer::LoadSettings);
}
}
//============ histograms
hMulti = new Histogram1D("Multiplicity", "", 10, 0, 10, this);
hMulti = new Histogram1D("Multiplicity", "", 16, 0, 16, this);
layout->addWidget(hMulti, 0, 1);
// the "this" make the histogram a child of the SplitPole class. When SplitPole destory, all childs destory as well.
h2D = new Histogram2D("Coincident Plot", "XXX", "YYY", 100, 0, 5000, 100, 0, 5000, this);
h2D = new Histogram2D("Coincident Plot", "XXX", "YYY", 200, 0, 30000, 200, 0, 30000, this, rawDataPath);
//layout is inheriatge from Analyzer
layout->addWidget(h2D, 1, 0, 2, 1);
@ -327,17 +381,16 @@ inline void CoincidentAnalyzer::SetUpCanvas(){
h2D->SetYTitle("Digi-" + QString::number(digi[bd]->GetSerialNumber()) + ", Ch-" + QString::number(ch));
h2D->UpdatePlot();
h1 = new Histogram1D("1D Plot", "XXX", 300, 0, 5000, this);
h1 = new Histogram1D("1D Plot", "XXX", 300, 0, 30000, this);
h1->SetColor(Qt::darkGreen);
h1->AddDataList("Test", Qt::red); // add another histogram in h1, Max Data List is 10
// h1->AddDataList("Test", Qt::red); // add another histogram in h1, Max Data List is 10
bd = aDigi->currentData().toInt();
ch = aCh->currentData().toInt();
h1->SetXTitle("Digi-" + QString::number(digi[bd]->GetSerialNumber()) + ", Ch-" + QString::number(ch));
h1->UpdatePlot();
layout->addWidget(h1, 1, 1);
h1g = new Histogram1D("1D Plot (PID gated)", "XXX", 300, 0, 5000, this);
h1g = new Histogram1D("1D Plot (PID gated)", "XXX", 300, 0, 30000, this);
h1g->SetXTitle("Digi-" + QString::number(digi[bd]->GetSerialNumber()) + ", Ch-" + QString::number(ch));
h1g->UpdatePlot();
layout->addWidget(h1g, 2, 1);
@ -345,17 +398,25 @@ inline void CoincidentAnalyzer::SetUpCanvas(){
layout->setColumnStretch(0, 1);
layout->setColumnStretch(1, 1);
allowSignalSlot = true;
}
inline void CoincidentAnalyzer::UpdateHistograms(){
// printf(">>>>>>>>>>>>> CoincidentAnalyzer::%s | %d %d %d \n", __func__, this->isVisible(), chkRunAnalyzer->isChecked(), isWorking);
if( this->isVisible() == false ) return;
if( chkRunAnalyzer->isChecked() == false ) return;
BuildEvents(); // call the event builder to build events
unsigned long long t0 = getTime_ns();
BuildEvents(false); // call the event builder to build events
// unsigned long long t1 = getTime_ns();
// printf("Event Build time : %llu ns = %.f msec\n", t1 - t0, (t1-t0)/1e6);
//============ Get events, and do analysis
long eventBuilt = evtbder->eventBuilt;
long eventBuilt = mb->eventBuilt;
if( eventBuilt == 0 ) return;
//============ Get the cut list, if any
@ -374,13 +435,17 @@ inline void CoincidentAnalyzer::UpdateHistograms(){
int y_bd = yDigi->currentData().toInt();
int y_ch = yCh->currentData().toInt();
int a_sn = digi[a_bd]->GetSerialNumber();
int x_sn = digi[x_bd]->GetSerialNumber();
int y_sn = digi[y_bd]->GetSerialNumber();
//============ Processing data and fill histograms
long eventIndex = evtbder->eventIndex;
long eventIndex = mb->eventIndex;
long eventStart = eventIndex - eventBuilt + 1;
if(eventStart < 0 ) eventStart += MaxNEvent;
for( long i = eventStart ; i <= eventIndex; i ++ ){
std::vector<Hit> event = evtbder->events[i];
std::vector<Hit> event = mb->events[i];
hMulti->Fill((int) event.size());
if( event.size() == 0 ) return;
@ -389,17 +454,17 @@ inline void CoincidentAnalyzer::UpdateHistograms(){
int xE = -1, yE = -1;
unsigned long long xT = 0;
for( int k = 0; k < (int) event.size(); k++ ){
//event[k].Print();
if( event[k].sn == a_bd && event[k].ch == a_ch) {
// event[k].Print();
if( event[k].sn == a_sn && event[k].ch == a_ch) {
h1->Fill(event[k].energy);
aE = event[k].energy;
}
if( event[k].sn == x_bd && event[k].ch == x_ch) {
if( event[k].sn == x_sn && event[k].ch == x_ch) {
xE = event[k].energy;
xT = event[k].timestamp;
}
if( event[k].sn == y_bd && event[k].ch == y_ch) yE = event[k].energy;
if( event[k].sn == y_sn && event[k].ch == y_ch) yE = event[k].energy;
}
if( xE >= 0 && yE >= 0 ) h2D->Fill(xE, yE);
@ -415,6 +480,10 @@ inline void CoincidentAnalyzer::UpdateHistograms(){
if( p == 0 && aE >= 0 ) h1g->Fill(aE); // only for the 1st gate
}
}
unsigned long long ta = getTime_ns();
if( ta - t0 > sbUpdateTime->value() * 0.9 * GetUpdateTimeInSec() * 1e9 ) break;
}
h2D->UpdatePlot();
@ -422,25 +491,177 @@ inline void CoincidentAnalyzer::UpdateHistograms(){
hMulti->UpdatePlot();
h1g->UpdatePlot();
// QList<QString> cutNameList = h2D->GetCutNameList();
// for( int p = 0; p < cutList.count(); p ++){
// if( cutList[p].isEmpty() ) continue;
// double dT = (tMax[p]-tMin[p]) * tick2ns / 1e9; // tick to sec
// double rate = count[p]*1.0/(dT);
//printf("%llu %llu, %f %d\n", tMin[p], tMax[p], dT, count[p]);
//printf("%10s | %d | %f Hz \n", cutNameList[p].toStdString().c_str(), count[p], rate);
// influx->AddDataPoint("Cut,name=" + cutNameList[p].toStdString()+ " value=" + std::to_string(rate));
// influx->WriteData(dataBaseName);
// influx->ClearDataPointsBuffer();
// }
if( influx ){
QList<QString> cutNameList = h2D->GetCutNameList();
for( int p = 0; p < cutList.count(); p ++){
if( cutList[p].isEmpty() ) continue;
double dT = (tMax[p]-tMin[p]) / 1e9;
double rate = count[p]*1.0/(dT);
// printf("%llu %llu, %f %d\n", tMin[p], tMax[p], dT, count[p]);
printf("%10s | %d | %f Hz \n", cutNameList[p].toStdString().c_str(), count[p], rate);
influx->AddDataPoint("Cut,name=" + cutNameList[p].toStdString()+ " value=" + std::to_string(rate));
}
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
}
}
inline void CoincidentAnalyzer::SaveHistRange(){
inline void CoincidentAnalyzer::SaveSettings(){
QString filePath = QFileDialog::getSaveFileName(this,
"Save Settings to File",
QDir::toNativeSeparators(rawDataPath + "/CoinAnaSettings.txt" ),
"Text file (*.txt)");
if (!filePath.isEmpty()){
QFile file(filePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&file);
// Define the text to write
QStringList lines;
lines << QString::number(digi[aDigi->currentData().toInt()]->GetSerialNumber());
lines << QString::number(aCh->currentData().toInt());
lines << QString::number(h1->GetNBin());
lines << QString::number(h1->GetXMin());
lines << QString::number(h1->GetXMax());
lines << QString::number(digi[xDigi->currentData().toInt()]->GetSerialNumber());
lines << QString::number(xCh->currentData().toInt());
lines << QString::number(h2D->GetXNBin());
lines << QString::number(h2D->GetXMin());
lines << QString::number(h2D->GetXMax());
lines << QString::number(digi[yDigi->currentData().toInt()]->GetSerialNumber());
lines << QString::number(yCh->currentData().toInt());
lines << QString::number(h2D->GetYNBin());
lines << QString::number(h2D->GetYMin());
lines << QString::number(h2D->GetYMax());
lines << QString::number(sbUpdateTime->value());
lines << QString::number(chkBackWardBuilding->isChecked());
lines << QString::number(sbBackwardCount->value());
lines<< dataBaseIP;
lines<< dataBaseName;
lines<< dataBaseToken;
lines << "#===== End of File";
// Write each line to the file
for (const QString &line : lines) out << line << "\n";
// Close the file
file.close();
qDebug() << "File written successfully to" << filePath;
}else{
qWarning() << "Unable to open file" << filePath;
}
}
}
inline void CoincidentAnalyzer::LoadHistRange(){
inline void CoincidentAnalyzer::LoadSettings(){
QString filePath = QFileDialog::getOpenFileName(this,
"Load Settings to File",
rawDataPath,
"Text file (*.txt)");
int a_sn, a_ch, a_bin;
float a_min, a_max;
int x_sn, x_ch, x_bin;
float x_min, x_max;
int y_sn, y_ch, y_bin;
float y_min, y_max;
float updateTime = 1.0;
int bkCount = 100;
bool isBkEvtBuild = false;
if (!filePath.isEmpty()) {
QFile file(filePath);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&file);
short count = 0;
while (!in.atEnd()) {
QString line = in.readLine();
if( count == 0 ) a_sn = line.toInt();
if( count == 1 ) a_ch = line.toInt();
if( count == 2 ) a_bin = line.toInt();
if( count == 3 ) a_min = line.toFloat();
if( count == 4 ) a_max = line.toFloat();
if( count == 5 ) x_sn = line.toFloat();
if( count == 6 ) x_ch = line.toFloat();
if( count == 7 ) x_bin = line.toFloat();
if( count == 8 ) x_min = line.toFloat();
if( count == 9 ) x_max = line.toFloat();
if( count == 10 ) y_sn = line.toFloat();
if( count == 11 ) y_ch = line.toFloat();
if( count == 12 ) y_bin = line.toFloat();
if( count == 13 ) y_min = line.toFloat();
if( count == 14 ) y_max = line.toFloat();
if( count == 15 ) updateTime = line.toFloat();
if( count == 16 ) isBkEvtBuild = line.toInt();
if( count == 17 ) bkCount = line.toInt();
if( count == 18 ) dataBaseIP = line;
if( count == 19 ) dataBaseName = line;
if( count == 20 ) dataBaseToken = line;
count ++;
}
file.close();
qDebug() << "File read successfully from" << filePath;
if( count >= 21 ){
sbUpdateTime->setValue(updateTime);
chkBackWardBuilding->setChecked(isBkEvtBuild);
sbBackwardCount->setValue(bkCount);
int x_index = xDigi->findText("Digi-" + QString::number(x_sn));
int y_index = yDigi->findText("Digi-" + QString::number(y_sn));
int a_index = aDigi->findText("Digi-" + QString::number(a_sn));
if( x_index == -1 ) qWarning() << " Cannot find digitizer " << x_sn;
if( y_index == -1 ) qWarning() << " Cannot find digitizer " << y_sn;
if( a_index == -1 ) qWarning() << " Cannot find digitizer " << a_sn;
xDigi->setCurrentIndex(x_index);
yDigi->setCurrentIndex(y_index);
aDigi->setCurrentIndex(a_index);
xCh->setCurrentIndex(x_ch);
yCh->setCurrentIndex(y_ch);
aCh->setCurrentIndex(a_ch);
h1->Rebin(a_bin, a_min, a_max);
h1g->Rebin(a_bin, a_min, a_max);
h2D->Rebin(x_bin, x_min, x_max, y_bin, y_min, y_max);
SetDatabase(dataBaseIP, dataBaseName, dataBaseToken);
if( influx ){
leDBName->setText(dataBaseName);
leInfluxIP->setText(dataBaseIP);
}
}
}else {
qWarning() << "Unable to open file" << filePath;
}
}
}

View File

@ -5,6 +5,8 @@
#include "Isotope.h"
#include <map>
#include <QApplication>
// #include <QScreen>
namespace EncoreChMap{
@ -82,8 +84,15 @@ private:
inline void Encore::SetUpCanvas(){
setGeometry(0, 0, 1600, 1600);
//====== resize window if screen too small
QScreen * screen = QGuiApplication::primaryScreen();
QRect screenGeo = screen->geometry();
if( screenGeo.width() < 1000 || screenGeo.height() < 1000) {
setGeometry(0, 0, screenGeo.width() - 100, screenGeo.height() -100);
}else{
setGeometry(0, 0, 1000, 1000);
}
// setGeometry(0, 0, 1600, 1600);
chkRunAnalyzer = new QCheckBox("Run Analyzer", this);
layout->addWidget(chkRunAnalyzer, 0, 0);

View File

@ -31,9 +31,7 @@ public:
evtbder = GetEventBuilder();
evtbder->SetTimeWindow(500); //ns
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
dataBaseName = "testing";
SetDatabase("https://localhost:8086", "testing", "zKhzKk4Yhf1l9QU-yE2GsIZ1RazqUgoW3NlF8LJqq_xDMwatOJwg1sKrjgq36uLEsQf8Fmn4sJALP7Kkilk14A==");
SetUpCanvas(); // see below
@ -251,7 +249,7 @@ inline void MCP::UpdateHistograms(){
//printf("%10s | %d | %f Hz \n", cutNameList[p].toStdString().c_str(), count[p], rate);
influx->AddDataPoint("Cut,name=" + cutNameList[p].toStdString()+ " value=" + std::to_string(rate));
influx->WriteData(dataBaseName);
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
}
}

View File

@ -28,9 +28,7 @@ public:
evtbder = GetEventBuilder();
evtbder->SetTimeWindow(500);
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
dataBaseName = "testing";
SetDatabase("https://localhost:8086", "testing", "zKhzKk4Yhf1l9QU-yE2GsIZ1RazqUgoW3NlF8LJqq_xDMwatOJwg1sKrjgq36uLEsQf8Fmn4sJALP7Kkilk14A==");
SetUpCanvas(); // see below

178
analyzers/MUSICAnalyzer.h Normal file
View File

@ -0,0 +1,178 @@
#ifndef MUSICANLAYZER_H
#define MUSICANLAYZER_H
#include "Analyser.h"
#include "Isotope.h"
#include <map>
#include <QApplication>
// #include <QScreen>
namespace MUSICChMap{
const std::map<unsigned short, int> SN2Bd = {
{16828, 0},
{16829, 1},
{16827, 2},
{23986, 3}
};
//Left 0->15
//Right 16->31
//Individual{32=Grid, 33=S0, 34=cathode, 35=S17, 36=Si_dE, 100>pulser},
//-1=empty
const int mapping[4][16] = {
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
{34, -1, 1, -1, 33, 101, 5, -1, 0, -1, 9, -1, 17, 13, -1, 32},
{ 2, -1, 16, -1, 21, 102, 20, -1, 8, -1, 24, -1, 27, 28, -1, 14},
{19, -1, 3, -1, 6, 103, 7, -1, 25, -1, 11, -1, 12, 15, -1, 10},
{ 4, -1, 18, 36, 23, 104, 22, -1, 29, -1, 26, -1, 31, 30, -1, 35}
};
// Gain matching [ch][bd]
const double corr[16][4] = {
{ 1.00000, 1.00000, 1.00000, 1.0000},
{ 1.00000, 1.00000, 1.03158, 1.0000},
{ 1.00000, 1.00000, 0.99240, 1.0000},
{ 1.00000, 1.03704, 0.94004, 1.0000},
{ 1.01031, 1.02084, 1.10114, 1.0000},
{ 1.00000, 0.94685, 1.00513, 1.0000},
{ 1.00000, 1.03431, 1.00513, 1.0000},
{ 1.00000, 0.92670, 0.96078, 1.0000},
{ 1.03431, 0.94685, 0.96314, 1.0000},
{ 1.00000, 1.03158, 0.95145, 1.0000},
{ 0.95145, 1.00256, 0.97270, 1.0000},
{ 1.00000, 1.00256, 0.90950, 1.0000},
{ 1.03704, 0.99492, 0.98740, 1.0000},
{ 1.00000, 1.00000, 0.99746, 1.0000},
{ 0.96078, 1.03980, 1.00513, 1.0000},
{ 1.00000, 1.05095, 1.00000, 1.0000},
};
};
class MUSIC : public Analyzer{
Q_OBJECT
public:
MUSIC(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent = nullptr): Analyzer(digi, nDigi, parent){
SetUpdateTimeInSec(1.0);
SetBackwardBuild(true, 100); // using normal building (acceding in time) or backward building, int the case of backward building, default events to be build is 100.
evtbder = GetEventBuilder();
evtbder->SetTimeWindow(10000);
SetUpCanvas();
}
// MUSIC(){};
void SetUpCanvas();
public slots:
void UpdateHistograms();
private:
MultiBuilder *evtbder;
Histogram2D * hLeft;
Histogram2D * hRight;
Histogram2D * hLR;
Histogram1D * hMulti;
QCheckBox * chkRunAnalyzer;
};
inline void MUSIC::SetUpCanvas(){
//====== resize window if screen too small
QScreen * screen = QGuiApplication::primaryScreen();
QRect screenGeo = screen->geometry();
if( screenGeo.width() < 1000 || screenGeo.height() < 1000) {
setGeometry(0, 0, screenGeo.width() - 100, screenGeo.height() -100);
}else{
setGeometry(0, 0, 1000, 1000);
}
// setGeometry(0, 0, 1600, 1600);
chkRunAnalyzer = new QCheckBox("Run Analyzer", this);
layout->addWidget(chkRunAnalyzer, 0, 0);
hLeft = new Histogram2D("Left", "Ch", "Energy", 16, 0, 16, 200, 0, 200, this);
layout->addWidget(hLeft, 1, 0);
hRight = new Histogram2D("Right", "Ch", "Energy", 16, 0, 16, 200, 0, 200, this);
layout->addWidget(hRight, 1, 1);
hLR = new Histogram2D("Left + Right", "Ch", "Energy", 17, 0, 16, 200, 0, 200, this);
layout->addWidget(hLR, 2, 0);
hMulti = new Histogram1D("Multi", "multiplicity", 40, 0, 40);
layout->addWidget(hMulti, 2, 1);
}
inline void MUSIC::UpdateHistograms(){
if( this->isVisible() == false ) return;
if( chkRunAnalyzer->isChecked() == false ) return;
BuildEvents(false); // call the event builder to build events
//============ Get events, and do analysis
long eventBuilt = evtbder->eventBuilt;
if( eventBuilt == 0 ) return;
//============ Processing data and fill histograms
long eventIndex = evtbder->eventIndex;
long eventStart = eventIndex - eventBuilt + 1;
if(eventStart < 0 ) eventStart += MaxNEvent;
// printf("MUSIC::%s----------- 2 : %ld %ld \n", __func__, eventStart, eventIndex);
for( long i = eventStart ; i <= eventIndex; i ++ ){
std::vector<Hit> event = evtbder->events[i];
// printf("MUSIC::%s----------- %ld, %zu\n", __func__, i, event.size());
hMulti->Fill((int) event.size());
if( event.size() == 0 ) return;
double sum[17] = {0};
for( int k = 0; k < (int) event.size(); k++ ){
// printf("--- %d\n", k);
int bd = MUSICChMap::SN2Bd.at(event[k].sn);
int ch = event[k].ch;
int ID = MUSICChMap::mapping[bd][ch];
if( ID < 0 ) continue;
double eC = event[k].energy;
if( 0 <= ID && ID < 16 ) {
eC *= MUSICChMap::corr[ch][bd];
hLeft->Fill(ID, eC);
sum[ID] += eC;
}
if( 16 <= ID && ID < 32 ) {
eC *= MUSICChMap::corr[ch][bd];
hRight->Fill(ID-16, eC );
sum[ID-16] += eC ;
}
}
for( int ch = 0; ch < 17; ch++){
if( sum[ch] > 0 ) hLR->Fill(ch, sum[ch]);
//printf("%d | sum %d\n", ch, sum[ch]);
}
}
hLeft->UpdatePlot();
hRight->UpdatePlot();
hMulti->UpdatePlot();
hLR->UpdatePlot();
}
#endif

239
analyzers/NeutronGamma.h Normal file
View File

@ -0,0 +1,239 @@
#ifndef NEUTRONGAMMA_H
#define NEUTRONGAMMA_H
/***********************************\
*
* This Analyzer does not use event builder,
* this simply use the energy_short and energy_long for each data.
*
*************************************/
#include <QMainWindow>
#include <QChart>
#include <QChartView>
#include <QLabel>
#include <QPushButton>
#include <QCheckBox>
#include <QLineEdit>
#include <QGridLayout>
#include <QGroupBox>
#include <QVector>
#include <QRandomGenerator>
#include "Analyser.h"
//^====================================================
//^====================================================
class NeutronGamma : public Analyzer{
Q_OBJECT
public:
NeutronGamma(Digitizer ** digi, unsigned int nDigi, QString rawDataPath, QMainWindow * parent = nullptr): Analyzer(digi, nDigi, parent){
this->digi = digi;
this->nDigi = nDigi;
this->settingPath = rawDataPath + "/NG_HistogramSettings.txt";
SetUpdateTimeInSec(1.0);
isSignalSlotActive = false;
SetUpCanvas();
ClearInternalDataCount();
};
~NeutronGamma(){
// for( unsigned int i = 0; i < nDigi; i++ ){
// for( int ch = 0; ch < digi[i]->GetNumInputCh(); ch++){
// delete hist2D[i][ch];
// }
// }
delete hist2D;
}
void ClearInternalDataCount();
// void LoadSetting();
// void SaveSetting();
public slots:
void UpdateHistograms();
private:
QVector<int> generateNonRepeatedCombination(int size);
void SetUpCanvas();
Digitizer ** digi;
unsigned short nDigi;
Histogram2D * hist2D;
RComboBox * cbDigi;
RComboBox * cbCh;
QGroupBox * histBox;
QGridLayout * histLayout;
int lastFilledIndex[MaxNDigitizer][MaxNChannels];
int loopFilledIndex[MaxNDigitizer][MaxNChannels];
bool fillHistograms;
QString settingPath;
unsigned short maxFillTimeinMilliSec;
unsigned short maxFillTimePerDigi;
bool isSignalSlotActive;
};
inline void NeutronGamma::SetUpCanvas(){
setWindowTitle("Neutron-Gamma Separation");
QScreen * screen = QGuiApplication::primaryScreen();
QRect screenGeo = screen->geometry();
if( screenGeo.width() < 1000 || screenGeo.height() < 800) {
setGeometry(0, 0, screenGeo.width() - 100, screenGeo.height() - 100);
}else{
setGeometry(0, 0, 1000, 800);
}
QWidget * layoutWidget = new QWidget(this);
setCentralWidget(layoutWidget);
QVBoxLayout * layout = new QVBoxLayout(layoutWidget);
layoutWidget->setLayout(layout);
{//^==================================
QGroupBox * controlBox = new QGroupBox("Control", this);
layout->addWidget(controlBox);
QGridLayout * ctrlLayout = new QGridLayout(controlBox);
controlBox->setLayout(ctrlLayout);
cbDigi = new RComboBox(this);
for( unsigned int i = 0; i < nDigi; i++) cbDigi->addItem("Digi-" + QString::number( digi[i]->GetSerialNumber() ), i);
ctrlLayout->addWidget(cbDigi, 0, 0, 1, 2);
connect( cbDigi, &RComboBox::currentIndexChanged, this, [=](int index){
isSignalSlotActive = false;
cbCh->clear();
for( int i = 0; i < digi[index]->GetNumInputCh(); i++) cbCh->addItem("ch-" + QString::number( i ), i);
hist2D->Clear();
isSignalSlotActive = true;
});
cbCh = new RComboBox(this);
for( int i = 0; i < digi[0]->GetNumInputCh(); i++) cbCh->addItem("ch-" + QString::number( i ), i);
ctrlLayout->addWidget(cbCh, 0, 2, 1, 2);
// connect( cbCh, &RComboBox::currentIndexChanged, this, &SingleSpectra::ChangeHistView);
connect( cbCh, &RComboBox::currentIndexChanged, this, [=](){
hist2D->Clear();
});
QCheckBox * chkIsFillHistogram = new QCheckBox("Fill Histograms", this);
ctrlLayout->addWidget(chkIsFillHistogram, 0, 8);
connect(chkIsFillHistogram, &QCheckBox::stateChanged, this, [=](int state){ fillHistograms = state;});
chkIsFillHistogram->setChecked(false);
fillHistograms = false;
QLabel * lbSettingPath = new QLabel( settingPath , this);
ctrlLayout->addWidget(lbSettingPath, 1, 0, 1, 8);
}
{//^====================================
histBox = new QGroupBox("Histgrams", this);
layout->addWidget(histBox, 10);
histLayout = new QGridLayout(histBox);
histBox->setLayout(histLayout);
double eMax = 50000;
double eMin = 0;
double nBin = 1000;
// for( unsigned int i = 0; i < MaxNDigitizer; i++){
// if( i >= nDigi ) continue;
// for( int j = 0; j < digi[i]->GetNumInputCh(); j++){
// if( i < nDigi ) {
// hist2D[i][j] = new Histogram2D("Digi-" + QString::number(digi[i]->GetSerialNumber()), "Long Energy [ch]", "Short Energy [ch]", nBin, eMin, eMax, nBin, eMin, eMax);
// }else{
// hist2D[i][j] = nullptr;
// }
// }
// }
// histLayout->addWidget(hist2D[0][0], 0, 0);
hist2D = new Histogram2D("Neutron-Gamma", "Long Energy [ch]", "PSD = (l-s)/l", nBin, eMin, eMax, nBin, 0, 1);
histLayout->addWidget(hist2D, 0, 0);
}
}
inline void NeutronGamma::ClearInternalDataCount(){
for( unsigned int i = 0; i < nDigi; i++){
for( int ch = 0; ch < MaxRegChannel ; ch++) {
lastFilledIndex[i][ch] = -1;
loopFilledIndex[i][ch] = 0;
}
}
}
inline void NeutronGamma::UpdateHistograms(){
if( !fillHistograms ) return;
if( this->isVisible() == false ) return;
int ID = cbDigi->currentData().toInt();
int ch = cbCh->currentData().toInt();
int lastIndex = digi[ID]->GetData()->GetDataIndex(ch);
if( lastIndex < 0 ) return;
int loopIndex = digi[ID]->GetData()->GetLoopIndex(ch);
int temp1 = lastIndex + loopIndex * digi[ID]->GetData()->GetDataSize();
int temp2 = lastFilledIndex[ID][ch] + loopFilledIndex[ID][ch] * digi[ID]->GetData()->GetDataSize() + 1;
if( temp1 - temp2 > digi[ID]->GetData()->GetDataSize() ) { //DefaultDataSize = 10k
temp2 = temp1 - digi[ID]->GetData()->GetDataSize();
lastFilledIndex[ID][ch] = lastIndex;
lastFilledIndex[ID][ch] = loopIndex - 1;
}
for( int j = 0 ; j <= temp1 - temp2; j ++){
lastFilledIndex[ID][ch] ++;
if( lastFilledIndex[ID][ch] > digi[ID]->GetData()->GetDataSize() ) {
lastFilledIndex[ID][ch] = 0;
loopFilledIndex[ID][ch] ++;
}
uShort data_long = digi[ID]->GetData()->GetEnergy(ch, lastFilledIndex[ID][ch]);
uShort data_short = digi[ID]->GetData()->GetEnergy2(ch, lastFilledIndex[ID][ch]);
// printf(" ch: %d, last fill idx : %d | %d \n", ch, lastFilledIndex[ID][ch], data);
double psd = (data_long - data_short) *1.0 / data_long;
hist2D->Fill(data_long, psd);
}
hist2D->UpdatePlot();
}
inline QVector<int> NeutronGamma::generateNonRepeatedCombination(int size) {
QVector<int> combination;
for (int i = 0; i < size; ++i) combination.append(i);
for (int i = 0; i < size - 1; ++i) {
int j = QRandomGenerator::global()->bounded(i, size);
combination.swapItemsAt(i, j);
}
return combination;
}
#endif

View File

@ -27,9 +27,7 @@ public:
evtbder = GetEventBuilder();
evtbder->SetTimeWindow(500);
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
dataBaseName = "testing";
SetDatabase("https://localhost:8086", "testing", "zKhzKk4Yhf1l9QU-yE2GsIZ1RazqUgoW3NlF8LJqq_xDMwatOJwg1sKrjgq36uLEsQf8Fmn4sJALP7Kkilk14A==");
SetUpCanvas(); // see below

134
analyzers/RAISOR.h Normal file
View File

@ -0,0 +1,134 @@
#ifndef RASIOR_h
#define RASIOR_h
/*********************************************
* This is online analyzer for RASIOR, ANL
*
* Created by Ryan @ 2023-10-16
*
* ******************************************/
#include "Analyser.h"
class RAISOR : public Analyzer{
public:
RAISOR(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent = nullptr): Analyzer(digi, nDigi, parent){
SetUpdateTimeInSec(1.0);
RedefineEventBuilder({0}); // only builder for the 0-th digitizer.
tick2ns = digi[0]->GetTick2ns();
SetBackwardBuild(false, 100); // using normal building (acceding in time) or backward building, int the case of backward building, default events to be build is 100.
evtbder = GetEventBuilder();
evtbder->SetTimeWindow(500);
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
dataBaseName = "testing";
SetUpCanvas(); // see below
};
void SetUpCanvas();
public slots:
void UpdateHistograms();
private:
MultiBuilder *evtbder;
Histogram2D * hPID;
int tick2ns;
float dE, E;
unsigned long long dE_t, E_t;
};
inline void RAISOR::SetUpCanvas(){
setGeometry(0, 0, 500, 500);
//============ histograms
hPID = new Histogram2D("RAISOR", "E", "dE", 100, 0, 5000, 100, 0, 20000, this);
layout->addWidget(hPID, 0, 0);
}
inline void RAISOR::UpdateHistograms(){
if( this->isVisible() == false ) return;
BuildEvents(false); // call the event builder to build events
//============ Get events, and do analysis
long eventBuilt = evtbder->eventBuilt;
if( eventBuilt == 0 ) return;
//============ Get the cut list, if any
QList<QPolygonF> cutList = hPID->GetCutList();
const int nCut = cutList.count();
unsigned long long tMin[nCut] = {0xFFFFFFFFFFFFFFFF}, tMax[nCut] = {0};
unsigned int count[nCut]={0};
//============ Processing data and fill histograms
long eventIndex = evtbder->eventIndex;
long eventStart = eventIndex - eventBuilt + 1;
if(eventStart < 0 ) eventStart += MaxNEvent;
for( long i = eventStart ; i <= eventIndex; i ++ ){
std::vector<Hit> event = evtbder->events[i];
//printf("-------------- %ld\n", i);
if( event.size() == 0 ) return;
for( int k = 0; k < (int) event.size(); k++ ){
//event[k].Print();
if( event[k].ch == 0 ) {dE = event[k].energy; dE_t = event[k].timestamp;}
if( event[k].ch == 1 ) {E = event[k].energy; E_t = event[k].timestamp;}
}
// printf("(E, dE) = (%f, %f)\n", E, dE);
hPID->Fill(E + RandomGauss(0, 100), dE+ RandomGauss(0, 100)); // x, y
//check events inside any Graphical cut and extract the rate
for(int p = 0; p < cutList.count(); p++ ){
if( cutList[p].isEmpty() ) continue;
if( cutList[p].containsPoint(QPointF(E, dE), Qt::OddEvenFill) ){
if( dE_t < tMin[p] ) tMin[p] = dE_t;
if( dE_t > tMax[p] ) tMax[p] = dE_t;
count[p] ++;
//printf(".... %d \n", count[p]);
}
}
}
hPID->UpdatePlot();
//========== output to Influx
QList<QString> cutNameList = hPID->GetCutNameList();
for( int p = 0; p < cutList.count(); p ++){
if( cutList[p].isEmpty() ) continue;
double dT = (tMax[p]-tMin[p]) * tick2ns / 1e9; // tick to sec
double rate = count[p]*1.0/(dT);
//printf("%llu %llu, %f %d\n", tMin[p], tMax[p], dT, count[p]);
//printf("%10s | %d | %f Hz \n", cutNameList[p].toStdString().c_str(), count[p], rate);
influx->AddDataPoint("Cut,name=" + cutNameList[p].toStdString()+ " value=" + std::to_string(rate));
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
}
}
#endif

View File

@ -25,9 +25,7 @@ public:
evtbder = GetEventBuilder();
evtbder->SetTimeWindow(500);
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
dataBaseName = "testing";
SetDatabase("https://localhost:8086", "testing", "zKhzKk4Yhf1l9QU-yE2GsIZ1RazqUgoW3NlF8LJqq_xDMwatOJwg1sKrjgq36uLEsQf8Fmn4sJALP7Kkilk14A==");
SetUpCanvas(); // see below
@ -261,7 +259,7 @@ inline void RAISOR1::UpdateHistograms(){
//printf("%10s | %d | %f Hz \n", cutNameList[p].toStdString().c_str(), count[p], rate);
influx->AddDataPoint("Cut,name=" + cutNameList[p].toStdString()+ " value=" + std::to_string(rate));
influx->WriteData(dataBaseName);
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
}
}

View File

@ -26,8 +26,7 @@ public:
evtbder->SetTimeWindow(500);
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
dataBaseName = "testing";
SetDatabase("https://localhost:8086", "testing", "zKhzKk4Yhf1l9QU-yE2GsIZ1RazqUgoW3NlF8LJqq_xDMwatOJwg1sKrjgq36uLEsQf8Fmn4sJALP7Kkilk14A==");
SetUpCanvas(); // see below
@ -289,7 +288,7 @@ inline void RAISOR2::UpdateHistograms(){
//printf("%10s | %d | %f Hz \n", cutNameList[p].toStdString().c_str(), count[p], rate);
influx->AddDataPoint("Cut,name=" + cutNameList[p].toStdString()+ " value=" + std::to_string(rate));
influx->WriteData(dataBaseName);
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
}
}

93
analyzers/README.md Normal file
View File

@ -0,0 +1,93 @@
# Introduction
This folder stored all online analyzers. The Analyser.cpp/h is the base class for all analyzer.
The Analyzer.cpp/h has the MultiBuilder (to handle event building) and InfluxDB (to handle pushing data to influxDB database) classes. In Addision, it has a QThread, a AnalyzerWorker, and a QTimer, these three object handle the threading of UpdateHistograms().
The AnalyzerWorker moves to the QThread. QTimer::timeout will trigger AnalyzerWorker::UpdateHistograms().
There is an important bool 'isWorking'. This boolean variable is true when AnalyzerWorker::UpdateHistograms() is running, and it is false when finsihed. This prevent UpdateHistograms() runs twice at the same time.
There are two virual methods
- SetupCanvas()
- UpdateHistograms()
Users must implement these two methods in theie custom analyzer.
# Intruction to make new Analyzer
The CoindientAnalyzer.h is a good example.
1. inheirate the Analyzer class
```cpp
class CustomAnalyzer : public Analyzer{
Q_OBJECT
public:
CustomAnalyzer(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent = nullptr): Analyzer(digi, nDigi, parent){
SetUpdateTimeInSec(1.0); // set histogram update period in sec
mb->SetTimeWindow(500); // set the event time windows
// ... other custom stuffs
}
void SetUpCanvas();
public slots:
void UpdateHistograms();
private:
Histogram2D * h2D;
Histogram1D * h1D;
// some priavte variables
}
```
2. implement the SetUpCanvas() method
```cpp
inline void CustomAnalyzer::SetUpCanvas(){
setWindowTitle("Title");
setGeometry(0, 0, 1600, 1000);
h2D = new Histogram2D("Coincident Plot", "XXX", "YYY", 200, 0, 30000, 200, 0, 30000, this, rawDataPath);
//layout is inheriatge from Analyzer
layout->addWidget(h2D, 0, 0); // row-0, col-0
h1 = new Histogram1D("1D Plot", "XXX", 300, 0, 30000, this);
h1->SetColor(Qt::darkGreen);
layout->addWidget(h1, 0, 1); // row-0, col-1
//other GUI elements
}
```
3. implement the UpdateHistograms() method
```cpp
inline void CustomAnalyzer::UpdateHistograms(){
// don't update histogram when the windows not visible
if( this->isVisible() == false ) return;
BuildEvents(false); // call the event builder to build events, no verbose
//check number of event built
long eventBuilt = mb->eventBuilt;
if( eventBuilt == 0 ) return;
//============ Processing data and fill histograms
long eventIndex = mb->eventIndex;
long eventStart = eventIndex - eventBuilt + 1;
if(eventStart < 0 ) eventStart += MaxNEvent;
for( long i = eventStart ; i <= eventIndex; i ++ ){
std::vector<Hit> event = mb->events[i];
//analysis and fill historgam
}
//Render histograms
h2D->UpdatePlot();
h1D->UpdatePlot();
}
```

View File

@ -30,8 +30,7 @@ public:
RedefineEventBuilder({0}); // only build for the 0-th digitizer, otherwise, it will build event accross all digitizers
tick2ns = digi[0]->GetTick2ns();
SetBackwardBuild(false, 100); // using normal building (acceding in time) or backward building, int the case of backward building, default events to be build is 100.
evtbder = GetEventBuilder();
evtbder->SetTimeWindow(500);
mb->SetTimeWindow(3000);
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
@ -41,7 +40,7 @@ public:
leTarget->setText("12C");
leBeam->setText("d");
leRecoil->setText("p");
sbBfield->setValue(0.76);
sbBfield->setValue(0.75);
sbAngle->setValue(20);
sbEnergy->setValue(16);
@ -67,8 +66,6 @@ public slots:
private:
MultiBuilder *evtbder;
// declaie histograms
Histogram2D * hPID;
@ -87,6 +84,7 @@ private:
RSpinBox * sbEnergy;
RSpinBox * sbAngle;
RSpinBox * sbEventWin;
QCheckBox * chkRunAnalyzer;
QLineEdit * leMassTablePath;
@ -212,9 +210,33 @@ inline void SplitPole::SetUpCanvas(){
FillConstants();
});
chkRunAnalyzer = new QCheckBox("Run Analyzer", this);
boxLayout->addWidget(chkRunAnalyzer, 4, 1);
QLabel * lbEventWindow = new QLabel("Event Window [ns] ", box);
lbEventWindow->setAlignment(Qt::AlignRight | Qt::AlignCenter);
boxLayout->addWidget(lbEventWindow, 4, 0);
sbEventWin = new RSpinBox(this);
sbEventWin->setDecimals(0);
sbEventWin->setSingleStep(100);
sbEventWin->setMaximum(1000000);
boxLayout->addWidget(sbEventWin, 4, 1);
sbEventWin->setValue(3000);
connect(sbEventWin, &RSpinBox::returnPressed, this, [=](){
mb->SetTimeWindow(sbEventWin->value());
});
chkRunAnalyzer = new QCheckBox("Run Analyzer", this);
boxLayout->addWidget(chkRunAnalyzer, 4, 3);
connect(chkRunAnalyzer, &QCheckBox::stateChanged, this, [=](int state){
sbBfield->setEnabled(state != Qt::Checked);
leTarget->setEnabled(state != Qt::Checked);
leBeam->setEnabled(state != Qt::Checked);
leRecoil->setEnabled(state != Qt::Checked);
sbEnergy->setEnabled(state != Qt::Checked);
sbAngle->setEnabled(state != Qt::Checked);
sbEventWin->setEnabled(state != Qt::Checked);
});
QFrame *separator = new QFrame(box);
separator->setFrameShape(QFrame::HLine);
@ -298,20 +320,20 @@ inline void SplitPole::SetUpCanvas(){
}
//============ histograms
hMulti = new Histogram1D("Multiplicity", "", 10, 0, 10, this);
hMulti = new Histogram1D("Multiplicity", "", 16, 0, 16, this);
layout->addWidget(hMulti, 0, 1);
// the "this" make the histogram a child of the SplitPole class. When SplitPole destory, all childs destory as well.
hPID = new Histogram2D("Split Pole PID", "Scin-L", "Anode-Font", 100, 0, 5000, 100, 0, 5000, this);
hPID = new Histogram2D("Split Pole PID", "Scin-L", "Anode-Back", 100, 0, 20000, 100, 0, 40000, this);
//layout is inheriatge from Analyzer
layout->addWidget(hPID, 1, 0, 2, 1);
h1 = new Histogram1D("Spectrum", "x", 300, 30, 70, this);
h1 = new Histogram1D("Spectrum", "x1", 300, -200, 200, this);
h1->SetColor(Qt::darkGreen);
//h1->AddDataList("Test", Qt::red); // add another histogram in h1, Max Data List is 10
layout->addWidget(h1, 1, 1);
h1g = new Histogram1D("Spectrum (PID gated)", "Ex", 300, -2, 10, this);
h1g = new Histogram1D("Spectrum (PID gated)", "x1", 300, -200, 200, this);
layout->addWidget(h1g, 2, 1);
layout->setColumnStretch(0, 1);
@ -327,7 +349,7 @@ inline void SplitPole::UpdateHistograms(){
BuildEvents(); // call the event builder to build events
//============ Get events, and do analysis
long eventBuilt = evtbder->eventBuilt;
long eventBuilt = mb->eventBuilt;
if( eventBuilt == 0 ) return;
//============ Get the cut list, if any
@ -337,12 +359,12 @@ inline void SplitPole::UpdateHistograms(){
unsigned int count[nCut]={0};
//============ Processing data and fill histograms
long eventIndex = evtbder->eventIndex;
long eventIndex = mb->eventIndex;
long eventStart = eventIndex - eventBuilt + 1;
if(eventStart < 0 ) eventStart += MaxNEvent;
for( long i = eventStart ; i <= eventIndex; i ++ ){
std::vector<Hit> event = evtbder->events[i];
std::vector<Hit> event = mb->events[i];
//printf("-------------- %ld\n", i);
hMulti->Fill((int) event.size());
@ -353,28 +375,32 @@ inline void SplitPole::UpdateHistograms(){
for( int k = 0; k < (int) event.size(); k++ ){
//event[k].Print();
if( event[k].ch == SPS::ChMap::ScinR ) {hit.eSR = event[k].energy; hit.tSR = event[k].timestamp;}
if( event[k].ch == SPS::ChMap::ScinL ) {hit.eSL = event[k].energy; hit.tSL = event[k].timestamp;}
if( event[k].ch == SPS::ChMap::dFR ) {hit.eFR = event[k].energy; hit.tFR = event[k].timestamp;}
if( event[k].ch == SPS::ChMap::dFL ) {hit.eFL = event[k].energy; hit.tFL = event[k].timestamp;}
if( event[k].ch == SPS::ChMap::dBR ) {hit.eBL = event[k].energy; hit.tBL = event[k].timestamp;}
if( event[k].ch == SPS::ChMap::dBL ) {hit.eBL = event[k].energy; hit.tBL = event[k].timestamp;}
if( event[k].ch == SPS::ChMap::Cathode ) {hit.eCath = event[k].energy; hit.tCath = event[k].timestamp;}
if( event[k].ch == SPS::ChMap::AnodeF ) {hit.eAF = event[k].energy; hit.tAF = event[k].timestamp;}
if( event[k].ch == SPS::ChMap::AnodeB ) {hit.eAB = event[k].energy; hit.tAB = event[k].timestamp;}
if( event[k].ch == SPS::ChMap::ScinR ) {hit.eSR = event[k].energy; hit.tSR = event[k].timestamp + event[k].fineTime/1000.;}
if( event[k].ch == SPS::ChMap::ScinL ) {hit.eSL = event[k].energy; hit.tSL = event[k].timestamp + event[k].fineTime/1000.;}
if( event[k].ch == SPS::ChMap::dFR ) {hit.eFR = event[k].energy; hit.tFR = event[k].timestamp + event[k].fineTime/1000.;}
if( event[k].ch == SPS::ChMap::dFL ) {hit.eFL = event[k].energy; hit.tFL = event[k].timestamp + event[k].fineTime/1000.;}
if( event[k].ch == SPS::ChMap::dBR ) {hit.eBL = event[k].energy; hit.tBL = event[k].timestamp + event[k].fineTime/1000.;}
if( event[k].ch == SPS::ChMap::dBL ) {hit.eBL = event[k].energy; hit.tBL = event[k].timestamp + event[k].fineTime/1000.;}
if( event[k].ch == SPS::ChMap::Cathode ) {hit.eCath = event[k].energy; hit.tCath = event[k].timestamp + event[k].fineTime/1000.;}
if( event[k].ch == SPS::ChMap::AnodeF ) {hit.eAF = event[k].energy; hit.tAF = event[k].timestamp + event[k].fineTime/1000.;}
if( event[k].ch == SPS::ChMap::AnodeB ) {hit.eAB = event[k].energy; hit.tAB = event[k].timestamp + event[k].fineTime/1000.;}
}
hit.CalData();
double pidX = hit.eSL;
unsigned long long tPidX = hit.tSL;
double pidY = hit.eAF;
double pidY = hit.eAB;
hPID->Fill(pidX, pidY); // x, y
h1->Fill(hit.xAvg);
if( pidX > 0 && pidY > 0 ){
hPID->Fill(pidX, pidY); // x, y
}
if( !std::isnan(hit.x1) ) {
h1->Fill(hit.x1);
}
//h1->Fill(hit.eSR, 1);
//check events inside any Graphical cut and extract the rate, using tSR only
for(int p = 0; p < cutList.count(); p++ ){
if( cutList[p].isEmpty() ) continue;
@ -383,10 +409,13 @@ inline void SplitPole::UpdateHistograms(){
if( tPidX > tMax[p] ) tMax[p] = tPidX;
count[p] ++;
//printf(".... %d \n", count[p]);
if( p == 0 ) {
double xAvg = hit.xAvg * 10;
double xAvgC = xAvg * sbRhoScale->value() + sbRhoOffset->value();
h1g->Fill(hit.Rho2Ex(xAvgC/1000.));
// if( p == 0 ) {
// double xAvg = hit.xAvg * 10;
// double xAvgC = xAvg * sbRhoScale->value() + sbRhoOffset->value();
// h1g->Fill(hit.Rho2Ex(xAvgC/1000.));
// }
if( p == 0 ){
h1g->Fill(hit.x1);
}
}
}
@ -406,7 +435,7 @@ inline void SplitPole::UpdateHistograms(){
//printf("%10s | %d | %f Hz \n", cutNameList[p].toStdString().c_str(), count[p], rate);
influx->AddDataPoint("Cut,name=" + cutNameList[p].toStdString()+ " value=" + std::to_string(rate));
influx->WriteData(dataBaseName);
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
}

View File

@ -39,8 +39,8 @@ namespace SPS{
const short ScinL = 1;
const short dFR = 9;
const short dFL = 8;
const short dBR = 10;
const short dBL = 11;
const short dBR = 11;
const short dBL = 10;
const short Cathode = 7;
const short AnodeF = 13;
const short AnodeB = 15;
@ -64,19 +64,19 @@ public:
ClearData();
}
unsigned int eSR; unsigned long long tSR;
unsigned int eSL; unsigned long long tSL;
unsigned int eFR; unsigned long long tFR;
unsigned int eFL; unsigned long long tFL;
unsigned int eBR; unsigned long long tBR;
unsigned int eBL; unsigned long long tBL;
unsigned int eSR; unsigned long long tSR;
unsigned int eSL; unsigned long long tSL;
unsigned int eFR; unsigned long long tFR;
unsigned int eFL; unsigned long long tFL;
unsigned int eBR; unsigned long long tBR;
unsigned int eBL; unsigned long long tBL;
unsigned int eCath; unsigned long long tCath;
unsigned int eAF; unsigned long long tAF;
unsigned int eAB; unsigned long long tAB;
unsigned int eAF; unsigned long long tAF;
unsigned int eAB; unsigned long long tAB;
float eSAvg;
float x1, x2, theta;
float xAvg;
double xAvg;
double GetQ0() const {return Q0;}
double GetRho0() const {return rho0;}
@ -194,14 +194,22 @@ public:
isConstantCal = false;
}
void CalData(){
void CalData(float scale = 2.){
if( eSR > 0 && eSL > 0 ) eSAvg = (eSR + eSL)/2;
if( eSR > 0 && eSL == 0 ) eSAvg = eSR;
if( eSR == 0 && eSL > 0 ) eSAvg = eSL;
if( tFR > 0 && tFL > 0 ) x1 = (tFL - tFR)/2./2.1;
if( tBR > 0 && tBL > 0 ) x2 = (tBL - tBR)/2./1.98;
if( tFR > 0 && tFL > 0 ) {
if( tFL > tFR) x1 = (tFL - tFR)/scale/2.1;
if( tFL < tFR) x1 = (tFR - tFL)/scale/-2.1;
}
if( tBR > 0 && tBL > 0 ) {
if( tBL > tBR) x2 = (tBL - tBR)/scale/1.98;
if( tBR > tBL) x2 = (tBR - tBL)/scale/-1.98;
}
// printf("x1: %f, x2 : %f \n", x1, x2);
if( !std::isnan(x1) && !std::isnan(x2)) {

View File

@ -25,9 +25,7 @@ public:
evtbder = GetEventBuilder();
evtbder->SetTimeWindow(500);
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
dataBaseName = "testing";
SetDatabase("https://localhost:8086", "testing", "zKhzKk4Yhf1l9QU-yE2GsIZ1RazqUgoW3NlF8LJqq_xDMwatOJwg1sKrjgq36uLEsQf8Fmn4sJALP7Kkilk14A==");
SetUpCanvas(); // see below
@ -183,7 +181,7 @@ inline void TEST::UpdateHistograms(){
for( int k = 0; k < (int) event.size(); k++ ){
//event[k].Print();
if( event[k].ch == 8 ) {dE = event[k].energy; dE_t = event[k].timestamp;} // Surface Barrier dE detector
if( event[k].ch == 8 ) {dE = event[k].energy; dE_t = event[k].timestamp;} // Surface Barrier dE detector
if( event[k].ch == 8 ) {E = event[k].energy; E_t = event[k].timestamp;} // Surface Barrier E detector
if( event[k].ch == 8 ) {e0 = event[k].energy; t0 = event[k].timestamp;} //
@ -199,20 +197,20 @@ inline void TEST::UpdateHistograms(){
hPID->Fill(E + RandomGauss(0, 100), dE + RandomGauss(0, 100)); // x, y
//hXX->Fill(e1 + RandomGauss(0, 100), e0 + RandomGauss(0, 100)); //
hXX->Fill(e1, e0 ); //
hYY->Fill(e3 + RandomGauss(0, 100), e2 + RandomGauss(0, 100));
hXY->Fill(((e0-e1)/(e0+e1)) + RandomGauss(0, 100),((e2-e3)/(e2+e3)) + RandomGauss(0, 100));
hXE->Fill(e0+e1);
hYE->Fill(e2+e3);
hX->Fill(((e0-e1)/(e0+e1)));
hY->Fill(((e2-e3)/(e2+e3)));
hXPE->Fill(((e0-e1)/(e0+e1)) + RandomGauss(0, 100),(e0+e1) + RandomGauss(0, 100));
hYPE->Fill(((e2-e3)/(e2+e3)) + RandomGauss(0, 100),(e2+e3) + RandomGauss(0, 100));
hXEdE1->Fill((e0+e1)+ RandomGauss(0, 100),dE1 + RandomGauss(0, 100));
hYEdE1->Fill((e2+e3) + RandomGauss(0, 100),dE1 + RandomGauss(0, 100));
hXEdE2->Fill((e0+e1)+ RandomGauss(0, 100),dE2 + RandomGauss(0, 100));
hYEdE2->Fill((e2+e3)+ RandomGauss(0, 100),dE2 + + RandomGauss(0, 100));
hXYE->Fill((e0+e1) + RandomGauss(0, 100),(e2+e3) + RandomGauss(0, 100));
hYY->Fill(e3 + RandomGauss(0, 100), e2 + RandomGauss(0, 100));
hXY->Fill(((e0-e1)/(e0+e1)) + RandomGauss(0, 100),((e2-e3)/(e2+e3)) + RandomGauss(0, 100));
hXE->Fill(e0+e1);
hYE->Fill(e2+e3);
hX->Fill(((e0-e1)/(e0+e1)));
hY->Fill(((e2-e3)/(e2+e3)));
hXPE->Fill(((e0-e1)/(e0+e1)) + RandomGauss(0, 100),(e0+e1) + RandomGauss(0, 100));
hYPE->Fill(((e2-e3)/(e2+e3)) + RandomGauss(0, 100),(e2+e3) + RandomGauss(0, 100));
hXEdE1->Fill((e0+e1)+ RandomGauss(0, 100),dE1 + RandomGauss(0, 100));
hYEdE1->Fill((e2+e3) + RandomGauss(0, 100),dE1 + RandomGauss(0, 100));
hXEdE2->Fill((e0+e1)+ RandomGauss(0, 100),dE2 + RandomGauss(0, 100));
hYEdE2->Fill((e2+e3)+ RandomGauss(0, 100),dE2 + + RandomGauss(0, 100));
hXYE->Fill((e0+e1) + RandomGauss(0, 100),(e2+e3) + RandomGauss(0, 100));
//check events inside any Graphical cut and extract the rate
for(int p = 0; p < cutList.count(); p++ ){
if( cutList[p].isEmpty() ) continue;
@ -264,7 +262,7 @@ inline void TEST::UpdateHistograms(){
//printf("%10s | %d | %f Hz \n", cutNameList[p].toStdString().c_str(), count[p], rate);
influx->AddDataPoint("Cut,name=" + cutNameList[p].toStdString()+ " value=" + std::to_string(rate));
influx->WriteData(dataBaseName);
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
}
}

View File

@ -27,9 +27,7 @@ public:
evtbder = GetEventBuilder();
evtbder->SetTimeWindow(500);
//========== use the influx from the Analyzer
influx = new InfluxDB("https://fsunuc.physics.fsu.edu/influx/");
dataBaseName = "testing";
SetDatabase("https://localhost:8086", "testing", "zKhzKk4Yhf1l9QU-yE2GsIZ1RazqUgoW3NlF8LJqq_xDMwatOJwg1sKrjgq36uLEsQf8Fmn4sJALP7Kkilk14A==");
SetUpCanvas(); // see below

View File

@ -11,6 +11,8 @@
#define MaxRecordLength 0x3fff * 8
#define MaxSaveFileSize 1024 * 1024 * 1024 * 2
#define ScalarUpdateinMiliSec 1000 // msec
#define MaxDisplayTraceTimeLength 20000 //ns
#define ScopeUpdateMiliSec 200 // msec
#define MaxNumberOfTrace 5 // in an event

View File

@ -3,6 +3,7 @@
#include <QProcess>
#include <QPushButton>
#include <QFile>
#include <QLocale>
#include "FSUDAQ.h"
@ -11,24 +12,28 @@
#include <sys/resource.h>
// class CustomApplication : public QApplication{
// public:
// CustomApplication(int &argc, char **argv) : QApplication(argc, argv) {}
#include <csignal>
#include <cstdlib>
#include <iostream>
// protected:
// bool notify(QObject *receiver, QEvent *event) override{
// qDebug() << event->type() << "Receiver:" << receiver;
// return QApplication::notify(receiver, event);
// }
// };
void abortHandler(int signal) {
std::cerr << "Signal received: " << signal << ", aborting..." << std::endl;
std::abort(); // Calls abort to generate core dump
}
int main(int argc, char *argv[]){
std::signal(SIGSEGV, abortHandler);
setpriority(PRIO_PROCESS, 0, -20);
// CustomApplication a(argc, argv);
QApplication a(argc, argv);
setpriority(PRIO_PROCESS, 0, -20);
// Set Locale
QLocale::setDefault(QLocale::system());
// Set Lock file
bool isLock = false;
int pid = 0;
QFile lockFile(DAQLockFile);
@ -70,7 +75,7 @@ int main(int argc, char *argv[]){
pidFile.write( QString::number(QCoreApplication::applicationPid() ).toStdString().c_str() );
pidFile.close();
MainWindow w;
FSUDAQ w;
w.show();
return a.exec();
}