diff --git a/.gitignore b/.gitignore index 371de72..c2361b7 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/.vscode/settings.json b/.vscode/settings.json index 05f7e93..7c56aa7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" } } \ No newline at end of file diff --git a/Aux/EventBuilder.cpp b/Aux/EventBuilder.cpp index 8183b1b..fe23f13 100644 --- a/Aux/EventBuilder.cpp +++ b/Aux/EventBuilder.cpp @@ -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 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 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; diff --git a/Aux/FSU2CAEN.cpp b/Aux/FSU2CAEN.cpp new file mode 100644 index 0000000..672e1a1 --- /dev/null +++ b/Aux/FSU2CAEN.cpp @@ -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> fileGroupList; // fileName and evID = SN * 1000 + index + std::vector 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 outFileName[numFileGroup]; + std::vector header[numFileGroup]; + std::vector 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 hitList[nGroup]; + + FSUReader ** reader = new FSUReader * [nGroup]; + ulong evID[nGroup]; + for( short i = 0; i < nGroup; i++){ + std::vector 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 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; + +} + diff --git a/Aux/Makefile b/Aux/Makefile index 27f7e4d..1433ca5 100644 --- a/Aux/Makefile +++ b/Aux/Makefile @@ -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" diff --git a/Aux/README.md b/Aux/README.md index 2e080c4..de72023 100644 --- a/Aux/README.md +++ b/Aux/README.md @@ -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 diff --git a/Aux/SettingsExplorer.cpp b/Aux/SettingsExplorer.cpp index 1fa495c..bfccf47 100644 --- a/Aux/SettingsExplorer.cpp +++ b/Aux/SettingsExplorer.cpp @@ -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{ diff --git a/Aux/SplitPolePlotter.C b/Aux/SplitPolePlotter.C new file mode 100644 index 0000000..387f88a --- /dev/null +++ b/Aux/SplitPolePlotter.C @@ -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 evID = {reader, "evID"}; + TTreeReaderValue multi = {reader, "multi"}; + TTreeReaderArray sn = {reader, "sn"}; + TTreeReaderArray ch = {reader, "ch"}; + TTreeReaderArray e = {reader, "e"}; + TTreeReaderArray e2 = {reader, "e2"}; + TTreeReaderArray e_t = {reader, "e_t"}; + TTreeReaderArray 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 \ No newline at end of file diff --git a/Aux/SplitPolePlotter_MT.C b/Aux/SplitPolePlotter_MT.C new file mode 100644 index 0000000..5f5dc9f --- /dev/null +++ b/Aux/SplitPolePlotter_MT.C @@ -0,0 +1,194 @@ +#include +#include "TTreeReader.h" +#include "TTreeReaderValue.h" +#include "TTreeReaderArray.h" +#include +#include +#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 pCoin("hCoin", "Coincident ", 16, 0, 16, 16, 0, 16); + ROOT::TThreadedObject phMulti("hMulti", "Multiplicity", 16, 0, 16); + ROOT::TThreadedObject pPID("hPID", "PID; Scin_X ; AnodeB", 200, 0, 20000, 100, 0, isFSUDAQ ? 40000 : 5000); + ROOT::TThreadedObject phXavg_Q("hXavg_Q", "Xavg vs Q ", 200, XMIN, XMAX, 200, 0, isFSUDAQ ? 40000 : 5000); + ROOT::TThreadedObject phF("hF", "Front delay line position", 600, XMIN, XMAX); + ROOT::TThreadedObject phB("hB", "Back delay line position", 600, XMIN, XMAX); + ROOT::TThreadedObject phXavg("hAvg", "Xavg", 600, XMIN, XMAX); + ROOT::TThreadedObject phFocal("hFocal", "Front vs Back ", 200, XMIN, XMAX, 200, XMIN, XMAX); + ROOT::TThreadedObject phXavg_Theta("hXavg_Theta", "Xavg vs Theta ", 200, XMIN, XMAX, 200, 0.5, 1.4); + ROOT::TThreadedObject phRay("hRay", "Ray plot", 400, XMIN, XMAX, 400, -50, 50); + ROOT::TThreadedObject phEx("hEx", "Ex; Ex [MeV]; count/10 keV", 600, -1, 5); + ROOT::TThreadedObject phEx_Multi("hEx_Multi", "Ex vs Multi; Ex; Multi", 600, -1, 5, 16, 0, 16); + + + //^==================== TTreeProcessorMT + ROOT::EnableImplicitMT(nThread); + + std::vector fileList_view; + std::vector 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 evID = {reader, "evID"}; + TTreeReaderValue multi = {reader, "multi"}; + TTreeReaderArray sn = {reader, "sn"}; + TTreeReaderArray ch = {reader, "ch"}; + TTreeReaderArray e = {reader, "e"}; + TTreeReaderArray e2 = {reader, "e2"}; + TTreeReaderArray e_t = {reader, "e_t"}; + TTreeReaderArray 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"); + +} \ No newline at end of file diff --git a/Aux/fsuReader.h b/Aux/fsuReader.h index fcc8450..6d9e3d0 100644 --- a/Aux/fsuReader.h +++ b/Aux/fsuReader.h @@ -3,7 +3,7 @@ #include #include -#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 ReadBatch(unsigned int batchSize = 1000000, bool verbose = false); // output the sorted Hit + std::vector 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 blockPos; std::vector 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 FSUReader::ReadBatch(unsigned int batchSize, bool verbose){ +inline std::vector 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 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 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; diff --git a/Aux/obsolete/EventBuilderNoTrace.cpp b/Aux/obsolete/EventBuilderNoTrace.cpp index acd2427..eb6d870 100644 --- a/Aux/obsolete/EventBuilderNoTrace.cpp +++ b/Aux/obsolete/EventBuilderNoTrace.cpp @@ -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() ); } } diff --git a/Aux/obsolete/EventBuilder_clumsy.cpp b/Aux/obsolete/EventBuilder_clumsy.cpp index 371c79e..e97376c 100644 --- a/Aux/obsolete/EventBuilder_clumsy.cpp +++ b/Aux/obsolete/EventBuilder_clumsy.cpp @@ -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(); diff --git a/Aux/script.C b/Aux/script.C index 0744458..2cebb08 100644 --- a/Aux/script.C +++ b/Aux/script.C @@ -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 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 hitList = reader->ReadBatch(10, true); + + // for ( int i = 0; i < 10 ; i ++) hitList[i].Print(); + + // // int ch = 5; + // // std::vector 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); -} \ No newline at end of file + // mb->BuildEventsBackWard(300); + + // mb->PrintAllEvent(); + // mb->PrintStat(); + + + // delete mb; + // delete reader; + +} diff --git a/Aux/test.cpp b/Aux/test.cpp index 7282f69..63966c2 100644 --- a/Aux/test.cpp +++ b/Aux/test.cpp @@ -321,82 +321,82 @@ int TestDigitizerRaw(){ } + +void Compare_CAEN_Decoder(){ + + std::unique_ptr digi = std::make_unique(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(&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(&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; } + //********************************* //********************************* diff --git a/ClassData.h b/ClassData.h index 92cbed4..39606c9 100644 --- a/ClassData.h +++ b/ClassData.h @@ -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); + } + } diff --git a/ClassDigitizer.cpp b/ClassDigitizer.cpp index 8d10f82..1c3bb54 100644 --- a/ClassDigitizer.cpp +++ b/ClassDigitizer.cpp @@ -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 ); diff --git a/ClassDigitizer.h b/ClassDigitizer.h index 6b7652f..6087493 100644 --- a/ClassDigitizer.h +++ b/ClassDigitizer.h @@ -206,6 +206,10 @@ class Digitizer{ return returnData; } + void SetTrace(bool onOff){ + SetBits(DPP::BoardConfiguration, DPP::Bit_BoardConfig::RecordTrace, onOff, -1); + } + }; diff --git a/CustomThreads.h b/CustomThreads.h index 6ee9d73..4251233 100644 --- a/CustomThreads.h +++ b/CustomThreads.h @@ -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.;} diff --git a/DigiSettingsPanel.cpp b/DigiSettingsPanel.cpp index f0f63b0..264a8a2 100644 --- a/DigiSettingsPanel.cpp +++ b/DigiSettingsPanel.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #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); diff --git a/DigiSettingsPanel.h b/DigiSettingsPanel.h index ea82950..495d972 100644 --- a/DigiSettingsPanel.h +++ b/DigiSettingsPanel.h @@ -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; diff --git a/FSUDAQ b/FSUDAQ new file mode 100755 index 0000000..04a3b23 --- /dev/null +++ b/FSUDAQ @@ -0,0 +1,7 @@ +#!/bin/bash + +timestamp=$(date +%Y%m%d_%H%M%S) + +outFile=program_${timestamp}.log + +stdbuf -oL ./FSUDAQ_Qt6 | tee $outFile \ No newline at end of file diff --git a/FSUDAQ.cpp b/FSUDAQ.cpp index 3dd349a..8a6a089 100644 --- a/FSUDAQ.cpp +++ b/FSUDAQ.cpp @@ -18,6 +18,9 @@ #include "analyzers/CoincidentAnalyzer.h" #include "analyzers/SplitPoleAnalyzer.h" #include "analyzers/EncoreAnalyzer.h" +#include "analyzers/MUSICAnalyzer.h" +#include "analyzers/NeutronGamma.h" + #include "analyzers/RAISOR1.h" #include "analyzers/RAISOR2.h" #include "analyzers/TEST.h" @@ -28,21 +31,21 @@ #include "analyzers/Target.h" #include "analyzers/BeamTune.h" +std::vector onlineAnalyzerList = {"Coincident","Splie-Pole", "Encore", "MUSICS", "Neutron-Gamma", "RAISOR1", "MCP", "PID", "RAISOR2", "TEST", "MCPandPSD", "Cross", "Target", "BeamTune"}; -std::vector onlineAnalyzerList = {"Coincident","Splie-Pole", "Encore", "RAISOR1", "MCP", "PID", "RAISOR2", "TEST", "MCPandPSD", "Cross", "Target", "BeamTune" }; - -MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ +FSUDAQ::FSUDAQ(QWidget *parent) : QMainWindow(parent){ DebugPrint("%s", "FSUDAQ"); setWindowTitle("FSU DAQ"); setGeometry(500, 100, 1100, 600); digi = nullptr; nDigi = 0; + isACQStarted= false; scalar = nullptr; scope = nullptr; digiSettings = nullptr; - canvas = nullptr; + singleHistograms = nullptr; onlineAnalyzer = nullptr; runTimer = new QTimer(); breakAutoRepeat = true; @@ -70,7 +73,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ //cbOpenDigitizers->addItem("Open Digitizers via USB", 3); cbOpenDigitizers->addItem("Open Digitizers via A4818(s)", 4); layout->addWidget(cbOpenDigitizers, 0, 0); - connect(cbOpenDigitizers, &RComboBox::currentIndexChanged, this, &MainWindow::OpenDigitizers); + connect(cbOpenDigitizers, &RComboBox::currentIndexChanged, this, &FSUDAQ::OpenDigitizers); cbOpenMethod = new RComboBox(this); cbOpenMethod->addItem("w/o settings", 0); @@ -80,29 +83,29 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ bnCloseDigitizers = new QPushButton("Close Digitizers", this); layout->addWidget(bnCloseDigitizers, 2, 0); - connect(bnCloseDigitizers, &QPushButton::clicked, this, &MainWindow::CloseDigitizers); + connect(bnCloseDigitizers, &QPushButton::clicked, this, &FSUDAQ::CloseDigitizers); bnDigiSettings = new QPushButton("Digitizers Settings", this); layout->addWidget(bnDigiSettings, 0, 1); - connect(bnDigiSettings, &QPushButton::clicked, this, &MainWindow::OpenDigiSettings); + connect(bnDigiSettings, &QPushButton::clicked, this, &FSUDAQ::OpenDigiSettings); bnOpenScope = new QPushButton("Open Scope", this); layout->addWidget(bnOpenScope, 1, 1); - connect(bnOpenScope, &QPushButton::clicked, this, &MainWindow::OpenScope); + connect(bnOpenScope, &QPushButton::clicked, this, &FSUDAQ::OpenScope); cbAnalyzer = new RComboBox(this); layout->addWidget(cbAnalyzer, 0, 2); cbAnalyzer->addItem("Choose Online Analyzer", -1); for( int i = 0; i < (int) onlineAnalyzerList.size() ; i++) cbAnalyzer->addItem(onlineAnalyzerList[i].c_str(), i); - connect(cbAnalyzer, &RComboBox::currentIndexChanged, this, &MainWindow::OpenAnalyzer); + connect(cbAnalyzer, &RComboBox::currentIndexChanged, this, &FSUDAQ::OpenAnalyzer); - bnCanvas = new QPushButton("Online 1D Histograms", this); + bnCanvas = new QPushButton("Online Histograms", this); layout->addWidget(bnCanvas, 1, 2); - connect(bnCanvas, &QPushButton::clicked, this, &MainWindow::OpenCanvas); + connect(bnCanvas, &QPushButton::clicked, this, &FSUDAQ::OpenSingleHistograms); bnSync = new QPushButton("Sync Boards", this); layout->addWidget(bnSync, 2, 1); - connect(bnSync, &QPushButton::clicked, this, &MainWindow::SetSyncMode); + connect(bnSync, &QPushButton::clicked, this, &FSUDAQ::SetSyncMode); } @@ -132,6 +135,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ leDatabaseName = new QLineEdit(this); leDatabaseName->setReadOnly(true); layout->addWidget(leDatabaseName, rowID, 4); + + chkInflux = new QCheckBox("Enable", this); + chkInflux->setChecked(true); + layout->addWidget(chkInflux, rowID, 5); rowID ++; QLabel * lbElogIP = new QLabel("Elog IP : ", this); @@ -150,7 +157,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ leElogName->setReadOnly(true); layout->addWidget(leElogName, rowID, 4); - connect(bnLock, &QPushButton::clicked, this, &MainWindow::SetAndLockInfluxElog); + chkElog = new QCheckBox("Enable", this); + chkElog->setChecked(true); + layout->addWidget(chkElog, rowID, 5); + + connect(bnLock, &QPushButton::clicked, this, &FSUDAQ::SetAndLockInfluxElog); } @@ -166,10 +177,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ leDataPath = new QLineEdit(this); leDataPath->setReadOnly(true); QPushButton * bnSetDataPath = new QPushButton("Set Path", this); - connect(bnSetDataPath, &QPushButton::clicked, this, &MainWindow::OpenDataPath); + connect(bnSetDataPath, &QPushButton::clicked, this, &FSUDAQ::OpenDataPath); QPushButton * bnOpenRecord = new QPushButton("Open Record", this); - connect(bnOpenRecord, &QPushButton::clicked, this, &MainWindow::OpenRecord); + connect(bnOpenRecord, &QPushButton::clicked, this, &FSUDAQ::OpenRecord); layout->addWidget(lbDataPath, rowID, 0); layout->addWidget(leDataPath, rowID, 1, 1, 5); @@ -185,7 +196,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ connect(lePrefix, &QLineEdit::textChanged, this, [=](){ lePrefix->setStyleSheet("color:blue;"); }); - connect(lePrefix, &QLineEdit::returnPressed, this, &MainWindow::SaveLastRunFile); + connect(lePrefix, &QLineEdit::returnPressed, this, &FSUDAQ::SaveLastRunFile); QLabel * lbRunID = new QLabel("Run No. :", this); lbRunID->setAlignment(Qt::AlignRight | Qt::AlignCenter); @@ -211,7 +222,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ cbAutoRun->setEnabled(false); bnStartACQ = new QPushButton("Start ACQ", this); - connect( bnStartACQ, &QPushButton::clicked, this, &MainWindow::AutoRun); + connect( bnStartACQ, &QPushButton::clicked, this, &FSUDAQ::AutoRun); bnStopACQ = new QPushButton("Stop ACQ", this); connect( bnStopACQ, &QPushButton::clicked, this, [=](){ if( runTimer->isActive() ){ @@ -243,7 +254,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ leComment->setReadOnly(true); bnOpenScaler = new QPushButton("Scalar", this); - connect(bnOpenScaler, &QPushButton::clicked, this, &MainWindow::OpenScalar); + connect(bnOpenScaler, &QPushButton::clicked, this, &FSUDAQ::OpenScalar); layout->addWidget(lbComment, rowID, 0); layout->addWidget(leComment, rowID, 1, 1, 6); @@ -300,18 +311,21 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ CheckElog(); - LogMsg("====== FSU DAQ is ready. ======"); - } -MainWindow::~MainWindow(){ +FSUDAQ::~FSUDAQ(){ DebugPrint("%s", "FSUDAQ"); if( scalar ) { - scalarThread->Stop(); - scalarThread->quit(); - scalarThread->exit(); + scalarTimingThread->Stop(); + scalarTimingThread->quit(); + scalarTimingThread->exit(); + // scalarTimer->stop(); + // if( scalarThread->isRunning() ){ + // scalarThread->quit(); + // scalarThread->exit(); + // } CleanUpScalar(); //don't need to delete scalar, it is managed by this } @@ -321,15 +335,7 @@ MainWindow::~MainWindow(){ if( scope ) delete scope; - if( histThread){ - histThread->Stop(); - histThread->quit(); - histThread->wait(); - - delete histThread; - } - - if( canvas ) delete canvas; + if( singleHistograms ) delete singleHistograms; if( onlineAnalyzer ) delete onlineAnalyzer; @@ -345,7 +351,7 @@ MainWindow::~MainWindow(){ //*************************************************************** //*************************************************************** -void MainWindow::OpenDataPath(){ +void FSUDAQ::OpenDataPath(){ DebugPrint("%s", "FSUDAQ"); QFileDialog fileDialog(this); fileDialog.setFileMode(QFileDialog::Directory); @@ -368,7 +374,7 @@ void MainWindow::OpenDataPath(){ } -void MainWindow::OpenRecord(){ +void FSUDAQ::OpenRecord(){ DebugPrint("%s", "FSUDAQ"); QString filePath = leDataPath->text() + "/RunTimeStamp.dat"; @@ -400,7 +406,7 @@ void MainWindow::OpenRecord(){ } -void MainWindow::UpdateRecord(){ +void FSUDAQ::UpdateRecord(){ DebugPrint("%s", "FSUDAQ"); if( !runRecord ) return; @@ -431,7 +437,7 @@ void MainWindow::UpdateRecord(){ tableView->scrollToBottom(); } -void MainWindow::LoadProgramSettings(){ +void FSUDAQ::LoadProgramSettings(){ DebugPrint("%s", "FSUDAQ"); LogMsg("Loading " + programSettingsFilePath + " for Program Settings."); QFile file(programSettingsFilePath); @@ -471,11 +477,11 @@ void MainWindow::LoadProgramSettings(){ LogMsg(" Raw Data Path : " + rawDataPath); LogMsg(" Influx IP : " + influxIP); LogMsg(" Database Name : " + dataBaseName); - LogMsg("Database Token : " + influxToken); + LogMsg("Database Token : " + maskText(influxToken)); LogMsg(" Elog IP : " + elogIP); LogMsg(" Elog Name : " + elogName); - LogMsg(" Elog User : " + elogUser); - LogMsg(" Elog PWD : " + elogPWD); + LogMsg(" Elog User : " + maskText(elogUser)); + LogMsg(" Elog PWD : " + maskText(elogPWD)); logMsgHTMLMode = true; //check is rawDataPath exist, if not, create one @@ -494,7 +500,7 @@ void MainWindow::LoadProgramSettings(){ } -void MainWindow::SaveProgramSettings(){ +void FSUDAQ::SaveProgramSettings(){ DebugPrint("%s", "FSUDAQ"); rawDataPath = leDataPath->text(); @@ -517,7 +523,7 @@ void MainWindow::SaveProgramSettings(){ } -void MainWindow::LoadLastRunFile(){ +void FSUDAQ::LoadLastRunFile(){ DebugPrint("%s", "FSUDAQ"); QFile file(rawDataPath + "/lastRun.sh"); @@ -558,7 +564,7 @@ void MainWindow::LoadLastRunFile(){ } -void MainWindow::SaveLastRunFile(){ +void FSUDAQ::SaveLastRunFile(){ DebugPrint("%s", "FSUDAQ"); QFile file(rawDataPath + "/lastRun.sh"); @@ -578,7 +584,7 @@ void MainWindow::SaveLastRunFile(){ //*************************************************************** //*************************************************************** -void MainWindow::OpenDigitizers(){ +void FSUDAQ::OpenDigitizers(){ DebugPrint("%s", "FSUDAQ"); if( cbOpenDigitizers->currentIndex() == 0 ) return; @@ -598,6 +604,7 @@ void MainWindow::OpenDigitizers(){ if( !file.open(QIODevice::Text | QIODevice::ReadOnly) ) { LogMsg("" + a4818Path + " not found."); LogMsg("Please create such file and put the a4818 PIDs inseperate lines."); + cbOpenDigitizers->setCurrentIndex(0); return; }else{ QTextStream in(&file); @@ -615,8 +622,8 @@ void MainWindow::OpenDigitizers(){ return; }else{ - if( a4818PIDs.size() > 4){ - LogMsg("There are more than 4 a4818, please edit the MaxNPorts in macro.h and recompile."); + if( a4818PIDs.size() > MaxNPorts){ + LogMsg("There are more than "+ QString::number(MaxNPorts) + " a4818, please edit the MaxNPorts in macro.h and recompile."); } } @@ -686,6 +693,9 @@ void MainWindow::OpenDigitizers(){ digi[i] = new Digitizer(portList[i].first, portList[i].second); //digi[i]->Reset(); + //===== set no trace, even when FSQDAQ segfault at scope, the digitizer will save no trace + digi[i]->SetTrace(false); + if( cbOpenMethod->currentData().toInt() == 2 ) { digi[i]->ProgramBoard(); } @@ -731,18 +741,12 @@ void MainWindow::OpenDigitizers(){ digi[i]->ReadAllSettingsFromBoard(true); readDataThread[i] = new ReadDataThread(digi[i], i); - connect(readDataThread[i], &ReadDataThread::sendMsg, this, &MainWindow::LogMsg); + connect(readDataThread[i], &ReadDataThread::sendMsg, this, &FSUDAQ::LogMsg); QCoreApplication::processEvents(); //to prevent Qt said application not responding. } - canvas = new SingleSpectra(digi, nDigi, rawDataPath); - histThread = new TimingThread(this); - histThread->SetWaitTimeinSec(canvas->GetMaxFillTime()/1000.); - connect(histThread, &TimingThread::timeUp, this, [=](){ - if( canvas == nullptr && !canvas->IsFillHistograms()) return; - canvas->FillHistograms(); - }); + singleHistograms = new SingleSpectra(digi, nDigi, rawDataPath); LogMsg("====== " + QString("Done. Opened %1 digitizer(s).").arg(nDigi) + " ====="); @@ -764,8 +768,8 @@ void MainWindow::OpenDigitizers(){ } -void MainWindow::CloseDigitizers(){ - LogMsg("MainWindow::Closing Digitizer(s)...."); +void FSUDAQ::CloseDigitizers(){ + LogMsg("FSUDAQ::Closing Digitizer(s)...."); if( scope ) { scope->close(); @@ -773,19 +777,17 @@ void MainWindow::CloseDigitizers(){ scope = nullptr; } - scalarThread->Stop(); - scalarThread->quit(); - scalarThread->exit(); - CleanUpScalar(); - - if( histThread){ - histThread->Stop(); - histThread->quit(); - histThread->wait(); - - delete histThread; - histThread = nullptr; + // scalarTimer->stop(); + // if( scalarThread->isRunning() ){ + // scalarThread->quit(); + // scalarThread->exit(); + // } + scalarTimingThread->Stop(); + if( scalarTimingThread->isRunning() ){ + scalarTimingThread->quit(); + scalarTimingThread->exit(); } + if( scalar ) CleanUpScalar(); if( onlineAnalyzer ){ onlineAnalyzer->close(); @@ -793,11 +795,10 @@ void MainWindow::CloseDigitizers(){ onlineAnalyzer = nullptr; } - - if( canvas ){ - canvas->close(); - delete canvas; - canvas = nullptr; + if( singleHistograms ){ + singleHistograms->close(); + delete singleHistograms; + singleHistograms = nullptr; } if( digiSettings ){ @@ -834,11 +835,11 @@ void MainWindow::CloseDigitizers(){ bnStartACQ->setStyleSheet(""); bnStopACQ->setStyleSheet(""); - printf("End of MainWindow::%s\n", __func__); + printf("End of FSUDAQ::%s\n", __func__); } -void MainWindow::WaitForDigitizersOpen(bool onOff){ +void FSUDAQ::WaitForDigitizersOpen(bool onOff){ DebugPrint("%s", "FSUDAQ"); // bnOpenDigitizers->setEnabled(onOff); @@ -863,7 +864,7 @@ void MainWindow::WaitForDigitizersOpen(bool onOff){ //*************************************************************** //*************************************************************** -void MainWindow::SetupScalar(){ +void FSUDAQ::SetupScalar(){ DebugPrint("%s", "FSUDAQ"); // printf("%s\n", __func__); @@ -889,9 +890,18 @@ void MainWindow::SetupScalar(){ lbScalarACQStatus = nullptr; lbTotalFileSize = nullptr; - scalarThread = new TimingThread(scalar); - scalarThread->SetWaitTimeinSec(1.0); - connect(scalarThread, &TimingThread::timeUp, this, &MainWindow::UpdateScalar); + scalarTimingThread = new TimingThread(scalar); + scalarTimingThread->SetWaitTimeinSec(ScalarUpdateinMiliSec / 1000.); + connect(scalarTimingThread, &TimingThread::timeUp, this, &FSUDAQ::UpdateScalar); + + // scalarThread = new QThread(this); + // scalarWorker = new ScalarWorker(this); + // scalarWorker->moveToThread(scalarThread); + + // scalarTimer = new QTimer(this); + // connect( scalarTimer, &QTimer::timeout, scalarWorker, &ScalarWorker::UpdateScalar); + + // scalarThread->start(); unsigned short maxNChannel = 0; for( unsigned int k = 0; k < nDigi; k ++ ){ @@ -1012,7 +1022,91 @@ void MainWindow::SetupScalar(){ } -void MainWindow::CleanUpScalar(){ +void FSUDAQ::UpdateScalar(){ + + DebugPrint("%s", "FSUDAQ"); + + // printf("================== FSUDAQ::%s\n", __func__); + + if( digi == nullptr ) return; + if( scalar == nullptr ) return; + //if( !scalar->isVisible() ) return; + + // digi[0]->GetData()->PrintAllData(); + + // lbLastUpdateTime->setText("Last update: " + QDateTime::currentDateTime().toString("MM.dd hh:mm:ss")); + lbLastUpdateTime->setText(QDateTime::currentDateTime().toString("MM/dd hh:mm:ss")); + scalarCount ++; + + uint64_t totalFileSize = 0; + for( unsigned int iDigi = 0; iDigi < nDigi; iDigi++){ + // printf("======== digi-%d\n", iDigi); + if( digi[iDigi]->IsBoardDisabled() ) continue; + + uint32_t acqStatus = digi[iDigi]->GetACQStatusFromMemory(); + //printf("Digi-%d : acq on/off ? : %d \n", digi[iDigi]->GetSerialNumber(), (acqStatus >> 2) & 0x1 ); + if( ( acqStatus >> 2 ) & 0x1 ){ + if( runStatus[iDigi]->styleSheet() == "") runStatus[iDigi]->setStyleSheet("background-color : green;"); + }else{ + if( runStatus[iDigi]->styleSheet() != "") runStatus[iDigi]->setStyleSheet(""); + } + + if(digiSettings && digiSettings->isVisible() && digiSettings->GetTabID() == iDigi) digiSettings->UpdateACQStatus(acqStatus); + + // digiMTX[iDigi].lock(); + + QString blockCountStr = QString::number(digi[iDigi]->GetData()->AggCount); + blockCountStr += "/" + QString::number(readDataThread[iDigi]->GetReadCount()); + readDataThread[iDigi]->SetReadCountZero(); + lbAggCount[iDigi]->setText(blockCountStr); + lbFileSize[iDigi]->setText(QString::number(digi[iDigi]->GetData()->GetTotalFileSize()/1024./1024., 'f', 3) + " MB"); + + digi[iDigi]->GetData()->CalTriggerRate(); //this will reset NumEventDecode & AggCount + if( chkSaveData->isChecked() ) totalFileSize += digi[iDigi]->GetData()->GetTotalFileSize(); + for( int i = 0; i < digi[iDigi]->GetNumInputCh(); i++){ + QString a = ""; + QString b = ""; + + if( digi[iDigi]->GetInputChannelOnOff(i) == true ) { + // printf(" %3d %2d | %7.2f %7.2f \n", digi[iDigi]->GetSerialNumber(), i, digi[iDigi]->GetData()->TriggerRate[i], digi[iDigi]->GetData()->NonPileUpRate[i]); + QString a = QString::number(digi[iDigi]->GetData()->TriggerRate[i], 'f', 2); + QString b = QString::number(digi[iDigi]->GetData()->NonPileUpRate[i], 'f', 2); + leTrigger[iDigi][i]->setText(a); + leAccept[iDigi][i]->setText(b); + + if( influx && chkInflux->isChecked() && a != "inf" ){ + influx->AddDataPoint("TrigRate,Bd="+std::to_string(digi[iDigi]->GetSerialNumber()) + ",Ch=" + QString::number(i).rightJustified(2, '0').toStdString() + " value=" + a.toStdString()); + } + + } + } + + // digiMTX[iDigi].unlock(); + // printf("============= end of FSUDAQ::%s\n", __func__); + + } + + lbTotalFileSize->setText("Total Data Size : " + QString::number(totalFileSize/1024./1024., 'f', 3) + " MB"); + + // repaint(); + // scalar->repaint(); + + if( influx && chkInflux->isChecked() && scalarCount >= 3){ + if( chkSaveData->isChecked() ) { + influx->AddDataPoint("RunID value=" + std::to_string(runID)); + influx->AddDataPoint("FileSize value=" + std::to_string(totalFileSize)); + } + //nflux->PrintDataPoints(); + influx->WriteData(dataBaseName.toStdString()); + influx->ClearDataPointsBuffer(); + scalarCount = 0; + } + + // printf("end of %s\n", __func__); + +} + +void FSUDAQ::CleanUpScalar(){ DebugPrint("%s", "FSUDAQ"); if( scalar == nullptr) return; @@ -1041,90 +1135,14 @@ void MainWindow::CleanUpScalar(){ } -void MainWindow::OpenScalar(){ +void FSUDAQ::OpenScalar(){ DebugPrint("%s", "FSUDAQ"); scalar->show(); } -void MainWindow::UpdateScalar(){ - DebugPrint("%s", "FSUDAQ"); - if( digi == nullptr ) return; - if( scalar == nullptr ) return; - //if( !scalar->isVisible() ) return; - - // digi[0]->GetData()->PrintAllData(); - - // lbLastUpdateTime->setText("Last update: " + QDateTime::currentDateTime().toString("MM.dd hh:mm:ss")); - lbLastUpdateTime->setText(QDateTime::currentDateTime().toString("MM/dd hh:mm:ss")); - scalarCount ++; - - uint64_t totalFileSize = 0; - for( unsigned int iDigi = 0; iDigi < nDigi; iDigi++){ - if( digi[iDigi]->IsBoardDisabled() ) continue; - - uint32_t acqStatus = digi[iDigi]->GetACQStatusFromMemory(); - //printf("Digi-%d : acq on/off ? : %d \n", digi[iDigi]->GetSerialNumber(), (acqStatus >> 2) & 0x1 ); - if( ( acqStatus >> 2 ) & 0x1 ){ - if( runStatus[iDigi]->styleSheet() == "") runStatus[iDigi]->setStyleSheet("background-color : green;"); - }else{ - if( runStatus[iDigi]->styleSheet() != "") runStatus[iDigi]->setStyleSheet(""); - } - - if(digiSettings && digiSettings->isVisible() && digiSettings->GetTabID() == iDigi) digiSettings->UpdateACQStatus(acqStatus); - - digiMTX[iDigi].lock(); - - QString blockCountStr = QString::number(digi[iDigi]->GetData()->AggCount); - blockCountStr += "/" + QString::number(readDataThread[iDigi]->GetReadCount()); - readDataThread[iDigi]->SetReadCountZero(); - lbAggCount[iDigi]->setText(blockCountStr); - lbFileSize[iDigi]->setText(QString::number(digi[iDigi]->GetData()->GetTotalFileSize()/1024./1024., 'f', 3) + " MB"); - - digi[iDigi]->GetData()->CalTriggerRate(); //this will reset NumEventDecode & AggCount - if( chkSaveData->isChecked() ) totalFileSize += digi[iDigi]->GetData()->GetTotalFileSize(); - for( int i = 0; i < digi[iDigi]->GetNumInputCh(); i++){ - QString a = ""; - QString b = ""; - - if( digi[iDigi]->GetInputChannelOnOff(i) == true ) { - // printf(" %3d %2d | %7.2f %7.2f \n", digi[iDigi]->GetSerialNumber(), i, digi[iDigi]->GetData()->TriggerRate[i], digi[iDigi]->GetData()->NonPileUpRate[i]); - QString a = QString::number(digi[iDigi]->GetData()->TriggerRate[i], 'f', 2); - QString b = QString::number(digi[iDigi]->GetData()->NonPileUpRate[i], 'f', 2); - leTrigger[iDigi][i]->setText(a); - leAccept[iDigi][i]->setText(b); - - if( influx && a != "inf" ){ - influx->AddDataPoint("TrigRate,Bd="+std::to_string(digi[iDigi]->GetSerialNumber()) + ",Ch=" + QString::number(i).rightJustified(2, '0').toStdString() + " value=" + a.toStdString()); - } - - } - } - - digiMTX[iDigi].unlock(); - - } - - lbTotalFileSize->setText("Total Data Size : " + QString::number(totalFileSize/1024./1024., 'f', 3) + " MB"); - - repaint(); - scalar->repaint(); - - if( influx && scalarCount >= 3){ - if( chkSaveData->isChecked() ) { - influx->AddDataPoint("RunID value=" + std::to_string(runID)); - influx->AddDataPoint("FileSize value=" + std::to_string(totalFileSize)); - } - //nflux->PrintDataPoints(); - influx->WriteData(dataBaseName.toStdString()); - influx->ClearDataPointsBuffer(); - scalarCount = 0; - } - -} - //*************************************************************** //*************************************************************** -void MainWindow::StartACQ(){ +void FSUDAQ::StartACQ(){ DebugPrint("%s", "FSUDAQ"); if( digi == nullptr ) return; @@ -1166,7 +1184,8 @@ void MainWindow::StartACQ(){ // printf("------------ Go! \n"); // for( unsigned int i = 0; i < nDigi; i++) readDataThread[i]->go(); - scalarThread->start(); + // if( scalar ) scalarTimer->start(ScalarUpdateinMiliSec); + if( scalar ) scalarTimingThread->start(); if( !scalar->isVisible() ) { scalar->show(); @@ -1175,7 +1194,8 @@ void MainWindow::StartACQ(){ } lbScalarACQStatus->setText("ACQ On"); - if( canvas != nullptr ) histThread->start(); + if( singleHistograms ) singleHistograms->startTimer(); + if( onlineAnalyzer ) onlineAnalyzer->startTimer(); bnStartACQ->setEnabled(false); bnStartACQ->setStyleSheet(""); @@ -1185,19 +1205,18 @@ void MainWindow::StartACQ(){ cbAutoRun->setEnabled(false); bnSync->setEnabled(false); - if( digiSettings ) digiSettings->setEnabled(false); + if( digiSettings ) digiSettings->EnableButtons(false); - if( onlineAnalyzer ) onlineAnalyzer->StartThread(); {//^=== elog and database - if( influx ){ + if( influx && chkInflux->isChecked() ){ influx->AddDataPoint("RunID value=" + std::to_string(runID)); if( !elogName.isEmpty() ) influx->AddDataPoint("SavingData,ExpName=" + elogName.toStdString() + " value=1"); influx->WriteData(dataBaseName.toStdString()); influx->ClearDataPointsBuffer(); } - if( elogID > 0 && chkSaveData->isChecked() ){ + if( elogID > 0 && !chkElog->isChecked() && chkSaveData->isChecked() ){ QString msg = "================================= Run-" + QString::number(runID).rightJustified(3, '0') + "

" + QDateTime::currentDateTime().toString("MM.dd hh:mm:ss") + "

" + startComment + "

" @@ -1206,12 +1225,13 @@ void MainWindow::StartACQ(){ } } + isACQStarted = true; chkSaveData->setEnabled(false); - bnDigiSettings->setEnabled(false); + // bnDigiSettings->setEnabled(false); } -void MainWindow::StopACQ(){ +void FSUDAQ::StopACQ(){ DebugPrint("%s", "FSUDAQ"); QCoreApplication::processEvents(); @@ -1240,23 +1260,18 @@ void MainWindow::StopACQ(){ if( chkSaveData->isChecked() ) digi[i]->GetData()->CloseSaveFile(); LogMsg("Digi-" + QString::number(digi[i]->GetSerialNumber()) + " ACQ is stopped." ); QCoreApplication::processEvents(); - digi[i]->ReadACQStatus(); } - if( scalarThread->isRunning()){ - scalarThread->Stop(); - scalarThread->quit(); - scalarThread->wait(); + if( scalarTimingThread->isRunning()){ + scalarTimingThread->Stop(); + scalarTimingThread->quit(); + scalarTimingThread->wait(); } - if( onlineAnalyzer ) onlineAnalyzer->StopThread(); - - if( canvas && histThread->isRunning()){ - histThread->Stop(); - histThread->quit(); - histThread->wait(); - canvas->ClearInternalDataCount(); - } + // if( scalar ) scalarTimer->stop(); + if( singleHistograms ) singleHistograms->stopTimer(); + if( onlineAnalyzer ) onlineAnalyzer->stopTimer(); + lbScalarACQStatus->setText("ACQ Off"); bnStartACQ->setEnabled(true); @@ -1279,16 +1294,19 @@ void MainWindow::StopACQ(){ } } - if( digiSettings ) digiSettings->setEnabled(true); + if( digiSettings ) { + digiSettings->EnableButtons(true); + digiSettings->ReadSettingsFromBoard(); + } {//^=== elog and database - if( influx && elogName != "" ) { + if( influx && chkInflux->isChecked() && elogName != "" ) { if( !elogName.isEmpty() ) influx->AddDataPoint("SavingData,ExpName=" + elogName.toStdString() + " value=0"); influx->WriteData(dataBaseName.toStdString()); influx->ClearDataPointsBuffer(); } - if( elogID > 0 && chkSaveData->isChecked()){ + if( elogID > 0 && !chkElog->isChecked() && chkSaveData->isChecked()){ QString msg = QDateTime::currentDateTime().toString("MM.dd hh:mm:ss") + "

" + stopComment + "

"; uint64_t totalFileSize = 0; for(unsigned int i = 0 ; i < nDigi; i++){ @@ -1304,14 +1322,15 @@ void MainWindow::StopACQ(){ } chkSaveData->setEnabled(true); - bnDigiSettings->setEnabled(true); + // bnDigiSettings->setEnabled(true); + isACQStarted = false; repaint(); - printf("================ end of %s \n", __func__); + // printf("================ end of %s \n", __func__); } -void MainWindow::AutoRun(){ +void FSUDAQ::AutoRun(){ DebugPrint("%s", "FSUDAQ"); runTimer->disconnect(runTimerConnection); if( chkSaveData->isChecked() == false){ @@ -1383,7 +1402,7 @@ void MainWindow::AutoRun(){ } -void MainWindow::SetSyncMode(){ +void FSUDAQ::SetSyncMode(){ DebugPrint("%s", "FSUDAQ"); QDialog dialog; dialog.setWindowTitle("Board Synchronization"); @@ -1479,7 +1498,7 @@ void MainWindow::SetSyncMode(){ } -void MainWindow::SetAndLockInfluxElog(){ +void FSUDAQ::SetAndLockInfluxElog(){ DebugPrint("%s", "FSUDAQ"); if( leInfluxIP->isReadOnly() ){ bnLock->setText("Lock and Set"); @@ -1599,7 +1618,7 @@ void MainWindow::SetAndLockInfluxElog(){ } } -bool MainWindow::CommentDialog(bool isStartRun){ +bool FSUDAQ::CommentDialog(bool isStartRun){ DebugPrint("%s", "FSUDAQ"); if( isStartRun ) runID ++; QString runIDStr = QString::number(runID).rightJustified(3, '0'); @@ -1680,7 +1699,7 @@ bool MainWindow::CommentDialog(bool isStartRun){ } -void MainWindow::WriteRunTimestamp(bool isStartRun){ +void FSUDAQ::WriteRunTimestamp(bool isStartRun){ DebugPrint("%s", "FSUDAQ"); QFile file(rawDataPath + "/RunTimeStamp.dat"); @@ -1688,9 +1707,9 @@ void MainWindow::WriteRunTimestamp(bool isStartRun){ if( file.open(QIODevice::Text | QIODevice::WriteOnly | QIODevice::Append) ){ if( isStartRun ){ - file.write(("Start Run | " + QString::number(runID) + " | " + dateTime + " | " + startComment + "\n").toStdString().c_str()); + file.write(("Start Run | " + QString::number(runID) + " | " + dateTime + " | " + lePrefix->text() + " | " + startComment + "\n").toStdString().c_str()); }else{ - file.write((" Stop Run | " + QString::number(runID) + " | " + dateTime + " | " + stopComment + "\n").toStdString().c_str()); + file.write((" Stop Run | " + QString::number(runID) + " | " + dateTime + " | " + lePrefix->text() + " | " + stopComment + "\n").toStdString().c_str()); } file.close(); @@ -1718,51 +1737,56 @@ void MainWindow::WriteRunTimestamp(bool isStartRun){ //*************************************************************** //*************************************************************** -void MainWindow::OpenScope(){ +void FSUDAQ::OpenScope(){ DebugPrint("%s", "FSUDAQ"); QCoreApplication::processEvents(); if( scope == nullptr ) { scope = new Scope(digi, nDigi, readDataThread); - connect(scope, &Scope::SendLogMsg, this, &MainWindow::LogMsg); + connect(scope, &Scope::SendLogMsg, this, &FSUDAQ::LogMsg); + connect(scope, &Scope::CloseWindow, this, [=](){ bnStartACQ->setEnabled(true); bnStartACQ->setStyleSheet("background-color: green;"); bnStopACQ->setEnabled(false); bnStopACQ->setStyleSheet(""); }); + connect(scope, &Scope::TellACQOnOff, this, [=](bool onOff){ - if( scope ) { - if( onOff ) { + + isACQStarted = onOff; + + if( onOff ){ + if( influx && chkInflux->isChecked() && !elogName.isEmpty()) influx->AddDataPoint("SavingData,ExpName=" + elogName.toStdString() + " value=1"); + + if( scalar ){ lbScalarACQStatus->setText("ACQ On"); - if( influx && !elogName.isEmpty()) influx->AddDataPoint("SavingData,ExpName=" + elogName.toStdString() + " value=1"); - }else{ + // scalarTimer->start(ScalarUpdateinMiliSec); + scalarTimingThread->start(); + } + + if( singleHistograms ) singleHistograms->startTimer(); + if( onlineAnalyzer ) onlineAnalyzer->startTimer(); + + }else{ + if( influx && chkInflux->isChecked() && !elogName.isEmpty()) influx->AddDataPoint("SavingData,ExpName=" + elogName.toStdString() + " value=0"); + + if( scalar ){ lbScalarACQStatus->setText("ACQ Off"); - if( influx && !elogName.isEmpty()) influx->AddDataPoint("SavingData,ExpName=" + elogName.toStdString() + " value=0"); - } - if( influx ){ - influx->WriteData(dataBaseName.toStdString()); - influx->ClearDataPointsBuffer(); + // scalarTimer->stop(); + scalarTimingThread->Stop(); + scalarTimingThread->quit(); + scalarTimingThread->wait(); } + + if( singleHistograms ) singleHistograms->stopTimer(); + if( onlineAnalyzer ) onlineAnalyzer->stopTimer(); + } - if( digiSettings ) digiSettings->setEnabled(!onOff); + if( digiSettings ) digiSettings->EnableButtons(!onOff); - if( canvas ){ - if( onOff) { - histThread->start(); - }else{ - if( histThread->isRunning()){ - histThread->Stop(); - histThread->quit(); - histThread->wait(); - canvas->ClearInternalDataCount(); - } - } - } }); - connect(scope, &Scope::UpdateScaler, this, &MainWindow::UpdateScalar); - connect(scope, &Scope::UpdateOtherPanels, this, [=](){ UpdateAllPanels(1); }); scope->show(); @@ -1781,11 +1805,11 @@ void MainWindow::OpenScope(){ //*************************************************************** //*************************************************************** -void MainWindow::OpenDigiSettings(){ +void FSUDAQ::OpenDigiSettings(){ DebugPrint("%s", "FSUDAQ"); if( digiSettings == nullptr ) { digiSettings = new DigiSettingsPanel(digi, nDigi, rawDataPath); - //connect(scope, &Scope::SendLogMsg, this, &MainWindow::LogMsg); + //connect(scope, &Scope::SendLogMsg, this, &FSUDAQ::LogMsg); connect(digiSettings, &DigiSettingsPanel::UpdateOtherPanels, this, [=](){ UpdateAllPanels(2); }); digiSettings->show(); @@ -1797,20 +1821,21 @@ void MainWindow::OpenDigiSettings(){ //*************************************************************** //*************************************************************** -void MainWindow::OpenCanvas(){ +void FSUDAQ::OpenSingleHistograms(){ DebugPrint("%s", "FSUDAQ"); - if( canvas == nullptr ) { - canvas = new SingleSpectra(digi, nDigi, rawDataPath); - canvas->show(); + if( singleHistograms == nullptr ) { + singleHistograms = new SingleSpectra(digi, nDigi, rawDataPath); + singleHistograms->show(); }else{ - canvas->show(); - canvas->activateWindow(); + singleHistograms->show(); + singleHistograms->activateWindow(); + singleHistograms->LoadSetting(); } } //*************************************************************** //*************************************************************** -void MainWindow::OpenAnalyzer(){ +void FSUDAQ::OpenAnalyzer(){ DebugPrint("%s", "FSUDAQ"); int id = cbAnalyzer->currentData().toInt(); @@ -1818,39 +1843,50 @@ void MainWindow::OpenAnalyzer(){ if( id < 0 ) return; if( onlineAnalyzer == nullptr ) { - //onlineAnalyzer = new Analyzer(digi, nDigi); - if( id == 0 ) onlineAnalyzer = new CoincidentAnalyzer(digi, nDigi); + if( id == 0 ) onlineAnalyzer = new CoincidentAnalyzer(digi, nDigi, rawDataPath); if( id == 1 ) onlineAnalyzer = new SplitPole(digi, nDigi); if( id == 2 ) onlineAnalyzer = new Encore(digi, nDigi); - if( id == 3 ) onlineAnalyzer = new RAISOR1(digi, nDigi); - if( id == 4 ) onlineAnalyzer = new MCP(digi, nDigi); - if( id == 5 ) onlineAnalyzer = new PID(digi, nDigi); - if( id == 6 ) onlineAnalyzer = new RAISOR2(digi, nDigi); - if( id == 7 ) onlineAnalyzer = new TEST(digi, nDigi); - if( id == 8 ) onlineAnalyzer = new MCPandPSD(digi, nDigi); - if( id == 9 ) onlineAnalyzer = new Cross(digi, nDigi); - if( id == 10 ) onlineAnalyzer = new Target(digi, nDigi); - if( id == 11 ) onlineAnalyzer = new BeamTune(digi, nDigi); + if( id == 3 ) onlineAnalyzer = new MUSIC(digi, nDigi); + if( id == 4 ) onlineAnalyzer = new NeutronGamma(digi, nDigi, rawDataPath); + + if( id == 5 ) onlineAnalyzer = new RAISOR1(digi, nDigi); + if( id == 6 ) onlineAnalyzer = new MCP(digi, nDigi); + if( id == 7 ) onlineAnalyzer = new PID(digi, nDigi); + if( id == 8 ) onlineAnalyzer = new RAISOR2(digi, nDigi); + if( id == 9 ) onlineAnalyzer = new TEST(digi, nDigi); + if( id == 10 ) onlineAnalyzer = new MCPandPSD(digi, nDigi); + if( id == 11 ) onlineAnalyzer = new Cross(digi, nDigi); + if( id == 12 ) onlineAnalyzer = new Target(digi, nDigi); + if( id == 13 ) onlineAnalyzer = new BeamTune(digi, nDigi); + if( id >= 0 ) onlineAnalyzer->show(); + + if( isACQStarted ) onlineAnalyzer->startTimer(); + }else{ delete onlineAnalyzer; - if( id == 0 ) onlineAnalyzer = new CoincidentAnalyzer(digi, nDigi); + if( id == 0 ) onlineAnalyzer = new CoincidentAnalyzer(digi, nDigi, rawDataPath); if( id == 1 ) onlineAnalyzer = new SplitPole(digi, nDigi); if( id == 2 ) onlineAnalyzer = new Encore(digi, nDigi); - if( id == 3 ) onlineAnalyzer = new RAISOR1(digi, nDigi); - if( id == 4 ) onlineAnalyzer = new MCP(digi, nDigi); - if( id == 5 ) onlineAnalyzer = new PID(digi, nDigi); - if( id == 6 ) onlineAnalyzer = new RAISOR2(digi, nDigi); - if( id == 7 ) onlineAnalyzer = new TEST(digi, nDigi); - if( id == 8 ) onlineAnalyzer = new MCPandPSD(digi, nDigi); - if( id == 9 ) onlineAnalyzer = new Cross(digi, nDigi); - if( id == 10 ) onlineAnalyzer = new Target(digi, nDigi); - if( id == 11 ) onlineAnalyzer = new BeamTune(digi, nDigi); + if( id == 3 ) onlineAnalyzer = new MUSIC(digi, nDigi); + if( id == 4 ) onlineAnalyzer = new NeutronGamma(digi, nDigi, rawDataPath); + + if( id == 5 ) onlineAnalyzer = new RAISOR1(digi, nDigi); + if( id == 6 ) onlineAnalyzer = new MCP(digi, nDigi); + if( id == 7 ) onlineAnalyzer = new PID(digi, nDigi); + if( id == 8 ) onlineAnalyzer = new RAISOR2(digi, nDigi); + if( id == 9 ) onlineAnalyzer = new TEST(digi, nDigi); + if( id == 10 ) onlineAnalyzer = new MCPandPSD(digi, nDigi); + if( id == 11 ) onlineAnalyzer = new Cross(digi, nDigi); + if( id == 12 ) onlineAnalyzer = new Target(digi, nDigi); + if( id == 13 ) onlineAnalyzer = new BeamTune(digi, nDigi); + if( id >= 0 ){ onlineAnalyzer->show(); onlineAnalyzer->activateWindow(); + if( isACQStarted ) onlineAnalyzer->stopTimer(); } } @@ -1860,7 +1896,7 @@ void MainWindow::OpenAnalyzer(){ //*************************************************************** //*************************************************************** -void MainWindow::UpdateAllPanels(int panelID){ +void FSUDAQ::UpdateAllPanels(int panelID){ DebugPrint("%s", "FSUDAQ"); //panelID is the source panel that call // scope = 1; @@ -1921,7 +1957,7 @@ void MainWindow::UpdateAllPanels(int panelID){ //*************************************************************** //*************************************************************** -void MainWindow::SetUpInflux(){ +void FSUDAQ::SetUpInflux(){ DebugPrint("%s", "FSUDAQ"); if( influxIP == "" ) { LogMsg("Influx missing inputs. skip."); @@ -1985,10 +2021,18 @@ void MainWindow::SetUpInflux(){ } -void MainWindow::CheckElog(){ +void FSUDAQ::CheckElog(){ + elogID = -1; DebugPrint("%s", "FSUDAQ"); + if( !chkElog->isChecked() ) { + LogMsg("Elog is disabled. Please chick the checkbox and lock again to check elog connectivity."); + leElogIP->setEnabled(false); + leElogName->setEnabled(false); + return; + } + LogMsg("---- Checking elog... please wait...."); - printf("---- Checking elog... please wait....\n"); + // printf("---- Checking elog... please wait....\n"); if( elogIP != "" && elogName != "" && elogUser != "" && elogPWD != "" ){ WriteElog("Testing communication.", "Testing communication.", "Other", 0); AppendElog("test append elog."); @@ -2001,13 +2045,13 @@ void MainWindow::CheckElog(){ if( elogID >= 0 ) { LogMsg("Elog testing OK."); - printf("Elog testing OK.\n"); + // printf("Elog testing OK.\n"); return; } //QMessageBox::information(nullptr, "Information", "Elog write Fail.\nPlease set the elog User and PWD in the programSettings.txt.\nline 6 = user.\nline 7 = pwd."); LogMsg("Elog testing Fail"); - printf("Elog testing Fail\n"); + // printf("Elog testing Fail\n"); if( elogIP == "" ) LogMsg("no elog IP"); if( elogName == "" ) LogMsg("no elog Name"); if( elogUser == "" ) LogMsg("no elog User name. Please set it in the programSettings.txt, line 6."); @@ -2018,9 +2062,10 @@ void MainWindow::CheckElog(){ } -void MainWindow::WriteElog(QString htmlText, QString subject, QString category, int runNumber){ +void FSUDAQ::WriteElog(QString htmlText, QString subject, QString category, int runNumber){ DebugPrint("%s", "FSUDAQ"); //if( elogID < 0 ) return; + if( !chkElog->isChecked() ) return; if( elogName == "" ) return; if( elogUser == "" ) return; if( elogPWD == "" ) return; @@ -2047,8 +2092,9 @@ void MainWindow::WriteElog(QString htmlText, QString subject, QString category, } -void MainWindow::AppendElog(QString appendHtmlText){ +void FSUDAQ::AppendElog(QString appendHtmlText){ DebugPrint("%s", "FSUDAQ"); + if( !chkElog->isChecked() )return; if( elogID < 1 ) return; if( elogName == "" ) return; @@ -2084,7 +2130,7 @@ void MainWindow::AppendElog(QString appendHtmlText){ //*************************************************************** //*************************************************************** -void MainWindow::LogMsg(QString msg){ +void FSUDAQ::LogMsg(QString msg){ DebugPrint("%s", "FSUDAQ"); QString outputStr = QStringLiteral("[%1] %2").arg(QDateTime::currentDateTime().toString("MM.dd hh:mm:ss"), msg); if( logMsgHTMLMode ){ diff --git a/FSUDAQ.h b/FSUDAQ.h index 120fd53..07f22d7 100644 --- a/FSUDAQ.h +++ b/FSUDAQ.h @@ -1,5 +1,5 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H +#ifndef FSUDAQ_H +#define FSUDAQ_H #include #include @@ -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 \ No newline at end of file diff --git a/FSUDAQ_Qt6.pro b/FSUDAQ_Qt6.pro index ec35cc4..8264124 100644 --- a/FSUDAQ_Qt6.pro +++ b/FSUDAQ_Qt6.pro @@ -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 \ diff --git a/Histogram1D.h b/Histogram1D.h index 9f531a7..a0f5704 100644 --- a/Histogram1D.h +++ b/Histogram1D.h @@ -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]; + }; diff --git a/Histogram2D.h b/Histogram2D.h index 88f8eed..33492b6 100644 --- a/Histogram2D.h +++ b/Histogram2D.h @@ -19,200 +19,20 @@ const QList> 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 cutList; - QList cutIDList; int numCut; + QList cutList; + QList cutNameList; // name of the cut + QList cutEntryList; // number of entry inside the cut. + QList cutIDList; // ID of the cut + QList cutTextIDList; // + QList plottableIDList; bool isDrawCut; int lastPlottableID; - QList cutTextIDList; - QList plottableIDList; - QList cutNameList; - QList 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 \ No newline at end of file diff --git a/MultiBuilder.cpp b/MultiBuilder.cpp index c7c8228..88d0e8d 100644 --- a/MultiBuilder.cpp +++ b/MultiBuilder.cpp @@ -7,15 +7,18 @@ MultiBuilder::MultiBuilder(Data ** multiData, std::vector 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); + } + } } diff --git a/MultiBuilder.h b/MultiBuilder.h index 9251b94..9fa8d13 100644 --- a/MultiBuilder.h +++ b/MultiBuilder.h @@ -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 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 dataSize; @@ -78,6 +81,8 @@ private: int lastBackWardIndex[MaxNDigitizer][MaxNChannels]; + bool forceStop; + }; diff --git a/README.md b/README.md index 9dd2f42..aa95aaa 100644 --- a/README.md +++ b/README.md @@ -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 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. +## 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 diff --git a/Scope.cpp b/Scope.cpp index 49e4fe0..372e719 100644 --- a/Scope.cpp +++ b/Scope.cpp @@ -6,6 +6,7 @@ #include #include #include +#include QVector Scope::TrapezoidFilter(QVector data, int baseLineEndS, int riseTimeS, int flatTopS, float decayTime_ns){ DebugPrint("%s", "Scope"); @@ -40,12 +41,12 @@ QVector Scope::TrapezoidFilter(QVector 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); diff --git a/Scope.h b/Scope.h index 2f2c769..be68607 100644 --- a/Scope.h +++ b/Scope.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -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 \ No newline at end of file diff --git a/SingleSpectra.cpp b/SingleSpectra.cpp index 40e2ad2..bc08501 100644 --- a/SingleSpectra.cpp +++ b/SingleSpectra.cpp @@ -4,12 +4,13 @@ #include #include #include +// #include 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 randomDigiList = generateNonRepeatedCombination(nDigi); @@ -304,17 +253,15 @@ void SingleSpectra::FillHistograms(){ QVector 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 data; + // if( list.count() != 4 ) { + // line = in.readLine(); + // continue; + // } + QVector 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__); + } } diff --git a/SingleSpectra.h b/SingleSpectra.h index 4e04a8f..9a0d19d 100644 --- a/SingleSpectra.h +++ b/SingleSpectra.h @@ -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 \ No newline at end of file diff --git a/analyzers/Analyser.cpp b/analyzers/Analyser.cpp index 5156c66..38330d0 100644 --- a/analyzers/Analyser.cpp +++ b/analyzers/Analyser.cpp @@ -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 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 idList){ delete mb; delete [] dataList; @@ -76,31 +166,70 @@ void Analyzer::RedefineEventBuilder(std::vector 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 idList = mb->GetDigiIDList(); - for( unsigned int i = 0; i < nData; i++ ) digiMTX[idList[i]].lock(); + // unsigned int nData = mb->GetNumOfDigitizer(); + // std::vector 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(); } diff --git a/analyzers/Analyser.h b/analyzers/Analyser.h index 5344bce..305b015 100644 --- a/analyzers/Analyser.h +++ b/analyzers/Analyser.h @@ -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 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 diff --git a/analyzers/BeamTune.h b/analyzers/BeamTune.h index 08a0e0e..a2fbdc9 100644 --- a/analyzers/BeamTune.h +++ b/analyzers/BeamTune.h @@ -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 lines; // Store lines to draw after the loop - //std::vector markers; // Store markers to draw after the loop - //int lineCount = 0; // Counter to keep track of the number of lines + //std::vector lines; // Store lines to draw after the loop + //std::vector 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 diff --git a/analyzers/CoincidentAnalyzer.h b/analyzers/CoincidentAnalyzer.h index 9113fe2..8b81450 100644 --- a/analyzers/CoincidentAnalyzer.h +++ b/analyzers/CoincidentAnalyzer.h @@ -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 event = evtbder->events[i]; + std::vector 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 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 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; + } + } } diff --git a/analyzers/EncoreAnalyzer.h b/analyzers/EncoreAnalyzer.h index b5a6b64..ad77632 100644 --- a/analyzers/EncoreAnalyzer.h +++ b/analyzers/EncoreAnalyzer.h @@ -5,6 +5,8 @@ #include "Isotope.h" #include +#include +// #include 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); diff --git a/analyzers/MCP.h b/analyzers/MCP.h index 3e4252d..4050960 100644 --- a/analyzers/MCP.h +++ b/analyzers/MCP.h @@ -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(); } } diff --git a/analyzers/MCPandPSD.h b/analyzers/MCPandPSD.h index f5e4726..8c1a5dc 100644 --- a/analyzers/MCPandPSD.h +++ b/analyzers/MCPandPSD.h @@ -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 diff --git a/analyzers/MUSICAnalyzer.h b/analyzers/MUSICAnalyzer.h new file mode 100644 index 0000000..c1d0913 --- /dev/null +++ b/analyzers/MUSICAnalyzer.h @@ -0,0 +1,178 @@ +#ifndef MUSICANLAYZER_H +#define MUSICANLAYZER_H + +#include "Analyser.h" +#include "Isotope.h" + +#include +#include +// #include + +namespace MUSICChMap{ + + const std::map 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 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 \ No newline at end of file diff --git a/analyzers/NeutronGamma.h b/analyzers/NeutronGamma.h new file mode 100644 index 0000000..94b10cf --- /dev/null +++ b/analyzers/NeutronGamma.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 NeutronGamma::generateNonRepeatedCombination(int size) { + QVector 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 \ No newline at end of file diff --git a/analyzers/PID.h b/analyzers/PID.h index 0cb91fb..5131619 100644 --- a/analyzers/PID.h +++ b/analyzers/PID.h @@ -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 diff --git a/analyzers/RAISOR.h b/analyzers/RAISOR.h new file mode 100644 index 0000000..e18c367 --- /dev/null +++ b/analyzers/RAISOR.h @@ -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 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 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 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 \ No newline at end of file diff --git a/analyzers/RAISOR1.h b/analyzers/RAISOR1.h index f828411..7263117 100644 --- a/analyzers/RAISOR1.h +++ b/analyzers/RAISOR1.h @@ -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(); } } diff --git a/analyzers/RAISOR2.h b/analyzers/RAISOR2.h index 7205307..99bfb84 100644 --- a/analyzers/RAISOR2.h +++ b/analyzers/RAISOR2.h @@ -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(); } } diff --git a/analyzers/README.md b/analyzers/README.md new file mode 100644 index 0000000..634104d --- /dev/null +++ b/analyzers/README.md @@ -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 event = mb->events[i]; + + //analysis and fill historgam + } + + //Render histograms + h2D->UpdatePlot(); + h1D->UpdatePlot(); + +} +``` \ No newline at end of file diff --git a/analyzers/SplitPoleAnalyzer.h b/analyzers/SplitPoleAnalyzer.h index cee5b81..088a1fe 100644 --- a/analyzers/SplitPoleAnalyzer.h +++ b/analyzers/SplitPoleAnalyzer.h @@ -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 event = evtbder->events[i]; + std::vector 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(); } diff --git a/analyzers/SplitPoleHit.h b/analyzers/SplitPoleHit.h index cd2d005..23f048a 100644 --- a/analyzers/SplitPoleHit.h +++ b/analyzers/SplitPoleHit.h @@ -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)) { diff --git a/analyzers/TEST.h b/analyzers/TEST.h index 3466b4c..fc545fc 100644 --- a/analyzers/TEST.h +++ b/analyzers/TEST.h @@ -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(); } } diff --git a/analyzers/Target.h b/analyzers/Target.h index 7a54be0..9372b46 100644 --- a/analyzers/Target.h +++ b/analyzers/Target.h @@ -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 diff --git a/macro.h b/macro.h index 32e8f5c..7562ba9 100644 --- a/macro.h +++ b/macro.h @@ -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 diff --git a/main.cpp b/main.cpp index 4f2ec66..e096e98 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "FSUDAQ.h" @@ -11,24 +12,28 @@ #include -// class CustomApplication : public QApplication{ -// public: -// CustomApplication(int &argc, char **argv) : QApplication(argc, argv) {} +#include +#include +#include -// 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(); } \ No newline at end of file