[MAJOR] Analayzer::UpdateHistograms moved to a worker that in a thread, only tested with CoincidentAnalyzer, need to change others

This commit is contained in:
Ryan Tang 2024-08-29 14:45:11 -04:00
parent a5914f8ff8
commit b3ace2cc84
7 changed files with 158 additions and 95 deletions

View File

@ -1173,6 +1173,7 @@ void FSUDAQ::StartACQ(){
lbScalarACQStatus->setText("<font style=\"color: green;\"><b>ACQ On</b></font>");
if( singleHistograms ) singleHistograms->startWork();
if( onlineAnalyzer ) onlineAnalyzer->startWork();
bnStartACQ->setEnabled(false);
bnStartACQ->setStyleSheet("");
@ -1184,7 +1185,6 @@ void FSUDAQ::StartACQ(){
if( digiSettings ) digiSettings->EnableButtons(false);
if( onlineAnalyzer ) onlineAnalyzer->StartThread();
{//^=== elog and database
if( influx && chkInflux->isChecked() ){
@ -1242,10 +1242,8 @@ void FSUDAQ::StopACQ(){
}
if( scalar ) scalarTimer->stop();
if( onlineAnalyzer ) onlineAnalyzer->StopThread();
if( singleHistograms ) singleHistograms->stopWork();
if( onlineAnalyzer ) onlineAnalyzer->stopWork();
lbScalarACQStatus->setText("<font style=\"color: red;\"><b>ACQ Off</b></font>");
@ -1815,7 +1813,7 @@ void FSUDAQ::OpenAnalyzer(){
if( id == 5 ) onlineAnalyzer = new NeutronGamma(digi, nDigi, rawDataPath);
if( id >= 0 ) onlineAnalyzer->show();
if( isACQStarted ) onlineAnalyzer->StartThread();
if( isACQStarted ) onlineAnalyzer->startWork();
}else{
@ -1831,7 +1829,7 @@ void FSUDAQ::OpenAnalyzer(){
if( id >= 0 ){
onlineAnalyzer->show();
onlineAnalyzer->activateWindow();
if( isACQStarted ) onlineAnalyzer->StartThread();
if( isACQStarted ) onlineAnalyzer->stopWork();
}
}

View File

@ -7,15 +7,18 @@ MultiBuilder::MultiBuilder(Data ** multiData, std::vector<int> type, std::vector
data = multiData;
typeList = type;
snList = sn;
numTotCh = 0;
for( uShort i = 0; i < nData; i++) {
idList.push_back(i);
dataSize.push_back(data[i]->GetDataSize());
numTotCh += data[i]->GetNChannel();
}
timeWindow = 100;
leftOverTime = 100;
breakTime = -1;
timeJump = 1e8;
lastEventTime = 0;
forceStop = false;
ClearEvents();
@ -29,6 +32,7 @@ MultiBuilder::MultiBuilder(Data * singleData, int type, int sn): nData(1){
DebugPrint("%s", "MultiBuilder");
data = new Data *[1];
data[0] = singleData;
numTotCh = data[0]->GetNChannel();
typeList.push_back(type);
snList.push_back(sn);
idList.push_back(0);
@ -37,7 +41,7 @@ MultiBuilder::MultiBuilder(Data * singleData, int type, int sn): nData(1){
breakTime = -1;
timeJump = 1e8;
lastEventTime = 0;
forceStop = false;
ClearEvents();
}
@ -57,6 +61,7 @@ void MultiBuilder::ClearEvents(){
loopIndex[i][j] = 0;
nextIndex[i][j] = -1;
chExhaused[i][j] = false;
lastBackWardIndex[i][j] = 0;
}
earlistDigi = -1;
@ -77,7 +82,6 @@ void MultiBuilder::PrintStat(){
if( nextIndex[i][ch] >= 0 ) printf("%d %3d %2d | %7d (%d)\n", i, snList[i], ch, nextIndex[i][ch], loopIndex[i][ch]);
}
}
}
void MultiBuilder::PrintAllEvent(){
@ -89,7 +93,6 @@ void MultiBuilder::PrintAllEvent(){
events[i][j].Print();
}
}
}
void MultiBuilder::FindEarlistTimeAndCh(bool verbose){
@ -100,22 +103,26 @@ void MultiBuilder::FindEarlistTimeAndCh(bool verbose){
nExhaushedCh = 0;
for( int i = 0; i < nData; i++){
for( int j = 0; j < data[i]->GetNChannel(); j++ ) chExhaused[i][j] = false;
for( int j = 0; j < data[i]->GetNChannel(); j++ ) {
chExhaused[i][j] = false;
}
for(unsigned int ch = 0; ch < data[i]->GetNChannel(); ch ++){
int index = data[i]->GetDataIndex(ch);
if( 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);
}
}
@ -147,7 +155,7 @@ void MultiBuilder::FindLatestTimeAndCh(bool verbose){
for(unsigned int ch = 0; ch < data[i]->GetNChannel(); ch ++){
if( nextIndex[i][ch] < 0 || 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,6 +219,7 @@ 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 for event building
FindEarlistTimeAndCh(verbose); //Give the earliest time, ch, digi
@ -221,6 +230,8 @@ void MultiBuilder::BuildEvents(bool isFinal, bool skipTrace, bool verbose){
Hit em;
do{
if( forceStop ) break;
eventIndex ++;
if( eventIndex >= MaxNEvent ) eventIndex = 0;
events[eventIndex].clear();
@ -339,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);
@ -359,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++){
@ -375,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;
}
@ -406,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++){
@ -424,24 +451,19 @@ void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){
break;
}
}
printf("%05d, %02d | %5d | %5d %llu \n", sn, chxxx, nextIndex[bd][chxxx], events[eventIndex][i].energy, events[eventIndex][i].timestamp);
printf("%5d, %02d | %5d | %5d %llu \n", sn, chxxx, nextIndex[bd][chxxx], events[eventIndex][i].energy, events[eventIndex][i].timestamp);
}
if( nExhaushedCh == nData * MaxNChannels ) {
printf("######################### no more event to be built\n");
break;
}
printf("----- next bd: %d, ch : %d, next latest Time : %llu.\n", latestDigi, latestCh, latestTime);
}
}while(nExhaushedCh < nData * MaxNChannels && eventBuilt < maxNumEvent);
}while(nExhaushedCh < numTotCh && eventBuilt < maxNumEvent);
// // remember the end of DataIndex, prevent over build
// for( int k = 0; k < nData; k++){
// for( int i = 0; i < MaxRegChannel; i++){
// lastBackWardIndex[k][i] = data[k]->DataIndex[i];
// }
// }
forceStop = false;
// remember the end of DataIndex, prevent over build
for( int k = 0; k < nData; k++){
for( int i = 0; i < data[k]->GetNChannel(); i++){
lastBackWardIndex[k][i] = data[k]->GetDataIndex(i);
}
}
}

View File

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

View File

@ -236,6 +236,7 @@ void SingleSpectra::ChangeHistView(){
void SingleSpectra::FillHistograms(){
// printf("%s | %d %d \n", __func__, chkIsFillHistogram->checkState(), isFillingHistograms);
if( this->isVisible() == false ) return;
if( chkIsFillHistogram->checkState() == Qt::Unchecked ) return;
if( isFillingHistograms) return;

View File

@ -30,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);
@ -42,19 +42,39 @@ 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;
anaWorker->UpdateHistograms();
});
// connect(anaWorker, &AnalyzerWorker::workDone, this, [=](){
// printf(" --------- work Done\n");
// });
anaThread->start();
}
Analyzer::~Analyzer(){
if( buildTimerThread ){
if( !buildTimerThread->isStopped() ){
buildTimerThread->Stop();
buildTimerThread->quit();
buildTimerThread->wait();
}
delete buildTimerThread;
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;
@ -144,28 +164,17 @@ void Analyzer::RedefineEventBuilder(std::vector<int> idList){
mb = new MultiBuilder(dataList, typeList, snList);
}
void Analyzer::StartThread(){
mb->ClearEvents();
buildTimerThread->start();
}
void Analyzer::StopThread(){
// printf("%s\n", __func__);
buildTimerThread->Stop();
buildTimerThread->quit();
buildTimerThread->wait();
}
void Analyzer::BuildEvents(bool verbose){
unsigned int nData = mb->GetNumOfDigitizer();
std::vector<int> idList = mb->GetDigiIDList();
// unsigned int nData = mb->GetNumOfDigitizer();
// std::vector<int> idList = mb->GetDigiIDList();
// for( unsigned int i = 0; i < nData; i++ ) digiMTX[idList[i]].lock();
if( isBuildBackward ){
mb->BuildEventsBackWard(maxNumEventBuilt, verbose);
}else{
mb->BuildEvents(0, true, verbose);
}
// mb->PrintStat();
// for( unsigned int i = 0; i < nData; i++ ) digiMTX[idList[i]].unlock();
}

View File

@ -38,7 +38,7 @@ and recompile FSUDAQ to incorporate the changes and activate the custom analyzer
#include "Histogram1D.h"
#include "Histogram2D.h"
// class AnalyzerWorker; //Forward decalration
class AnalyzerWorker; //Forward decalration
//^==============================================
//^==============================================
@ -56,27 +56,40 @@ public:
void SetDatabase(QString IP, QString Name, QString Token);
double RandomGauss(double mean, double sigma);
public slots:
void StartThread();
void StopThread();
void SetDatabaseButton();
double GetUpdateTimeInSec() const {return waitTimeinSec;}
virtual void SetUpCanvas();
virtual void UpdateHistograms(); // where event-building, analysis, and ploting
public slots:
void startWork(){
// printf("start timer\n");
mb->ForceStop(false);
mb->ClearEvents();
anaTimer->start(waitTimeinSec*1000);
}
void stopWork(){
// 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;
QString dataBaseIP;
QString dataBaseName;
QString dataBaseToken;
bool isWorking; // a flag to indicate the worker is working
private:
Digitizer ** digi;
unsigned short nDigi;
@ -90,29 +103,33 @@ private:
MultiBuilder * mb;
bool isBuildBackward;
int maxNumEventBuilt;
TimingThread * buildTimerThread;
// TimingThread * buildTimerThread;
QThread * anaThread;
AnalyzerWorker * anaWorker;
QTimer * anaTimer;
};
//^================================================ AnalyzerWorker
// class ScalarWorker : public QObject{
// Q_OBJECT
// public:
// ScalarWorker(Analyzer * parent): SS(parent){}
class AnalyzerWorker : public QObject{
Q_OBJECT
public:
AnalyzerWorker(Analyzer * parent): SS(parent){}
// public slots:
// void UpdateScalar(){
// SS->UpdateHistograms();
// emit workDone();
// }
public slots:
void UpdateHistograms(){
SS->UpdateHistograms();
emit workDone();
}
// signals:
// void workDone();
signals:
void workDone();
// private:
// Analyzer * SS;
// };
private:
Analyzer * SS;
};
#endif

View File

@ -403,16 +403,22 @@ inline void CoincidentAnalyzer::SetUpCanvas(){
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;
if( isWorking ) return;
isWorking = true; // This is important. set the isWorking = true to prevent another call of UpdateHistograms()
unsigned long long t0 = getTime_ns();
BuildEvents(); // call the event builder to build events
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;
if( eventBuilt == 0 ) return;
//============ Get the cut list, if any
@ -450,7 +456,7 @@ 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();
// event[k].Print();
if( event[k].sn == a_sn && event[k].ch == a_ch) {
h1->Fill(event[k].energy);
aE = event[k].energy;
@ -478,10 +484,11 @@ inline void CoincidentAnalyzer::UpdateHistograms(){
}
unsigned long long ta = getTime_ns();
if( ta - t0 > sbUpdateTime->value() * 0.9 * 1e9 ) break;
if( ta - t0 > sbUpdateTime->value() * 0.9 * GetUpdateTimeInSec() * 1e9 ) break;
}
// printf("--------------- update histograms\n");
h2D->UpdatePlot();
h1->UpdatePlot();
hMulti->UpdatePlot();
@ -502,6 +509,10 @@ inline void CoincidentAnalyzer::UpdateHistograms(){
influx->WriteData(dataBaseName.toStdString());
influx->ClearDataPointsBuffer();
}
// printf("<<<<<<<<<<<<< end of UpdateHistorgams\n");
isWorking = false;
}
inline void CoincidentAnalyzer::SaveSettings(){