From 17b1a7be1ff85a04dc83e5f7a165f6f3892647b2 Mon Sep 17 00:00:00 2001
From: Wudr-1995 <wudr@ihep.ac.cn>
Date: Thu, 28 Sep 2023 10:48:52 +0800
Subject: [PATCH] Create new tools and update README

---
 Analysis/CMakeLists.txt                       |   1 +
 Analysis/HitRateAnaTool/src/HitRateAnaTool.cc |   4 +-
 Analysis/HitRateDisAnaTool/CMakeLists.txt     |   4 +
 .../python/HitRateDisAnaTool/__init__.py      |   2 +
 .../src/HitRateDisAnaTool.cc                  | 177 ++++++++++++++++++
 .../HitRateDisAnaTool/src/HitRateDisAnaTool.h |  83 ++++++++
 README.md                                     |  36 ++++
 share/getHitRateDis.py                        |  53 ++++++
 share/getNoise.py                             |  46 +++++
 share/hitRateDisToolList                      |   1 +
 share/noiseToolList                           |   1 +
 11 files changed, 406 insertions(+), 2 deletions(-)
 create mode 100644 Analysis/HitRateDisAnaTool/CMakeLists.txt
 create mode 100644 Analysis/HitRateDisAnaTool/python/HitRateDisAnaTool/__init__.py
 create mode 100644 Analysis/HitRateDisAnaTool/src/HitRateDisAnaTool.cc
 create mode 100644 Analysis/HitRateDisAnaTool/src/HitRateDisAnaTool.h
 create mode 100644 share/getHitRateDis.py
 create mode 100644 share/getNoise.py
 create mode 100644 share/hitRateDisToolList
 create mode 100644 share/noiseToolList

diff --git a/Analysis/CMakeLists.txt b/Analysis/CMakeLists.txt
index dd206f7..b4897b3 100644
--- a/Analysis/CMakeLists.txt
+++ b/Analysis/CMakeLists.txt
@@ -5,3 +5,4 @@ add_subdirectory(IntervalTimeAnaTool)
 add_subdirectory(ChargeAnaTool)
 add_subdirectory(HitSpecAnaTool)
 add_subdirectory(HitRateAnaTool)
+add_subdirectory(HitRateDisAnaTool)
diff --git a/Analysis/HitRateAnaTool/src/HitRateAnaTool.cc b/Analysis/HitRateAnaTool/src/HitRateAnaTool.cc
index aaa46da..190c948 100644
--- a/Analysis/HitRateAnaTool/src/HitRateAnaTool.cc
+++ b/Analysis/HitRateAnaTool/src/HitRateAnaTool.cc
@@ -189,7 +189,7 @@ bool HitRateAnaTool::output() {
 			// m_rateCh[i]->SetPoint(j, j + 1, static_cast<double>(m_hitsPerCycle[i].at(j)) / TCYCLE);
 			double err = getStd(m_hitsPerCycle[i], j, j + 10);
 			m_rateCh[i]->SetPoint(np, j / 10 + 1, times * nHits / time);
-			m_rateCh[i]->SetPointError(np, 0, times * err / TMath::Sqrt(time / TCYCLE));
+			m_rateCh[i]->SetPointError(np, 0, err / TMath::Sqrt(nHits));
 
 			if (m_catiHitsPerCyc[i / 16].size() > j / 10) {
 				m_catiHitsPerCyc[i / 16].at(j / 10) += nHits;
@@ -213,7 +213,7 @@ bool HitRateAnaTool::output() {
 		m_rateCat[i]->Set(size);
 		for (int j = 0; j < size; j ++) {
 			m_rateCat[i]->SetPoint(np, j + 1, times * m_catiHitsPerCyc[i].at(j) / m_catiTimePerCyc[i].at(j));
-			m_rateCat[i]->SetPointError(np, 0, times * TMath::Sqrt(m_catiErroPerCyc[i].at(j)));
+			m_rateCat[i]->SetPointError(np, 0, TMath::Sqrt(m_catiErroPerCyc[i].at(j) / m_catiHitsPerCyc[i].at(j)));
 			np ++;
 		}
 	}
diff --git a/Analysis/HitRateDisAnaTool/CMakeLists.txt b/Analysis/HitRateDisAnaTool/CMakeLists.txt
new file mode 100644
index 0000000..7dc2faa
--- /dev/null
+++ b/Analysis/HitRateDisAnaTool/CMakeLists.txt
@@ -0,0 +1,4 @@
+PKG(HitRateDisAnaTool
+	DEPENDS
+		AnaTool
+)
diff --git a/Analysis/HitRateDisAnaTool/python/HitRateDisAnaTool/__init__.py b/Analysis/HitRateDisAnaTool/python/HitRateDisAnaTool/__init__.py
new file mode 100644
index 0000000..5099770
--- /dev/null
+++ b/Analysis/HitRateDisAnaTool/python/HitRateDisAnaTool/__init__.py
@@ -0,0 +1,2 @@
+import Sniper as sn
+sn.loadDll("libHitRateDisAnaTool.so")
diff --git a/Analysis/HitRateDisAnaTool/src/HitRateDisAnaTool.cc b/Analysis/HitRateDisAnaTool/src/HitRateDisAnaTool.cc
new file mode 100644
index 0000000..abdacd1
--- /dev/null
+++ b/Analysis/HitRateDisAnaTool/src/HitRateDisAnaTool.cc
@@ -0,0 +1,177 @@
+#include "HitRateDisAnaTool.h"
+
+DECLARE_TOOL(HitRateDisAnaTool);
+HitRateDisAnaTool::HitRateDisAnaTool(const string &name)
+	: ToolBase(name)
+{
+	declProp("HighRate", m_hrFlag = 1);
+}
+
+HitRateDisAnaTool::~HitRateDisAnaTool() {}
+
+bool HitRateDisAnaTool::configure(string outDir, SPMTMap *spmtMap) {
+	LogInfo << "configuring..." << endl;
+	m_outDir = outDir;
+	m_spmtMap = spmtMap;
+	m_nPoint = 0;
+
+	m_canvas.reset(new TCanvas("", "", 4000, 4000));
+	m_hitsPerCh.reset(new TH1F("", "HitsPerChannel;Channel;nHit", NCH, 0, NCH));
+	m_timePerCh.reset(new TH1F("", "TimePerChannel;Channel;DAQ time", NCH, 0, NCH));
+	m_rateDis.reset(new TGraph2D());
+	m_hitsPerCh->SetDirectory(0);
+	m_timePerCh->SetDirectory(0);
+	m_rateDis->SetDirectory(0);
+
+	m_nCycle = 0;
+	m_lastNCycle = -1;
+
+	m_rateCh.reserve(NCH);
+
+	for (int i = 0; i < NCH; i ++) {
+		TString tmp("Ch ");
+		tmp += i;
+		m_rateCh.push_back(make_unique<TGraphErrors>());
+		m_rateCh[i]->SetMarkerColor(kRed);
+		m_rateCh[i]->SetLineColor(kBlack);
+		m_rateCh[i]->SetMarkerStyle(26);
+		m_rateCh[i]->GetYaxis()->SetTitle(tmp + " hit rate / Hz");
+		m_rateCh[i]->GetXaxis()->SetTitle("Time / (16.7 s)");
+	}
+
+	std::fill(m_stTime, m_stTime + NCH, -1);
+	std::fill(m_edTime, m_edTime + NCH, -1);
+	std::fill(m_lastCoarseTimes, m_lastCoarseTimes + NCH, -1);
+	std::fill(m_cycle, m_cycle + NCH, -1);
+	std::fill(m_hits, m_hits + NCH, 0);
+	return true;
+}
+
+bool HitRateDisAnaTool::reset() {
+
+	m_hitsPerCh->Reset("ICE");
+	m_timePerCh->Reset("ICE");
+	for (int i = 0; i < NCH; i ++) {
+		m_hitsPerCycle[i].clear();
+		m_timePerCyc[i].clear();
+		m_rateCh[i]->Set(0);
+	}
+
+	for (int i = 0; i < 8; i ++) {
+		m_catiHitsPerCyc[i].clear();
+		m_catiTimePerCyc[i].clear();
+		m_catiErroPerCyc[i].clear();
+	}
+
+	std::fill(m_stTime, m_stTime + NCH, -1);
+	std::fill(m_edTime, m_edTime + NCH, -1);
+	std::fill(m_lastCoarseTimes, m_lastCoarseTimes + NCH, -1);
+	std::fill(m_cycle, m_cycle + NCH, -1);
+	std::fill(m_hits, m_hits + NCH, 0);
+
+	m_nCycle = 0;
+	m_lastNCycle = -1;
+	return true;
+}
+
+bool HitRateDisAnaTool::analyze(const Params& paras) {
+	m_evtType = paras.get("EventType");
+	m_abcCh = paras.get("ABCChannelNumber");
+	m_gcuId = paras.get("GCUId");
+	m_runNum = paras.get("RunNum");
+	m_coarseTime = paras.get("CoarseTime");
+	m_fineTime = paras.get("FineTime");
+
+	m_hitsPerCh->Fill(m_abcCh);
+
+	if (m_stTime[m_abcCh] = -1) {
+		m_stTime[m_abcCh] = m_coarseTime;
+	}
+
+	if (m_cycle[m_abcCh] == -1 || m_cycle[m_abcCh] == paras.get("OverflowCounter")) {
+		m_hits[m_abcCh] ++;
+		if (m_coarseTime > m_edTime[m_abcCh])
+			m_edTime[m_abcCh] = m_coarseTime;
+		if (m_coarseTime < m_stTime[m_abcCh])
+			m_stTime[m_abcCh] = m_coarseTime;
+	}
+	else {
+		if (m_nCycle - m_hitsPerCycle[m_abcCh].size() > 1) {
+			for (int i = 0; i < (m_nCycle - m_hitsPerCycle[m_abcCh].size() - 1); i ++)
+				m_hitsPerCycle[m_abcCh].push_back(0);
+		}
+		m_hitsPerCycle[m_abcCh].push_back(m_hits[m_abcCh]);
+		if (m_hitsPerCycle[m_abcCh].size() > m_nCycle)
+			m_nCycle = m_hitsPerCycle[m_abcCh].size();
+		m_hits[m_abcCh] = 1;
+		m_timePerCyc[m_abcCh].push_back(25 * static_cast<double>(m_edTime[m_abcCh] - m_stTime[m_abcCh]));
+		m_stTime[m_abcCh] = m_coarseTime;
+		m_edTime[m_abcCh] = m_coarseTime;
+	}
+
+	m_cycle[m_abcCh] = paras.get("OverflowCounter");
+	m_timePerCh->SetBinContent(m_abcCh + 1, m_cycle[m_abcCh] * TCYCLE + m_coarseTime * 25);
+	m_lastCoarseTimes[m_abcCh] = m_coarseTime;
+
+	return true;
+}
+
+bool HitRateDisAnaTool::output() {
+	TString outFile(m_outDir);
+	outFile += "_";
+	outFile += to_string(m_runNum);
+	if (m_evtType)
+		outFile += "_Phy";
+	else
+		outFile += "_Ped";
+	m_outPdf = outFile + "_hists.pdf";
+	m_outTxt = outFile + "_stat.txt";
+
+	LogInfo << "Output gcu " << m_gcuId << ", run " << m_runNum << endl;
+	LogInfo << "PDF dir: " << m_outPdf << endl;
+	LogInfo << "TXT dir: " << m_outTxt << endl;
+
+	for (int i = 0; i < NCH; i ++) {
+		m_hitsPerCycle[i].push_back(m_hits[i]);
+		m_timePerCyc[i].push_back(25 * static_cast<double>(m_edTime[i] - m_stTime[i]));
+	}
+
+	double times = 1;
+	if (m_hrFlag)
+		times = TCYCLE / 12.5E-3;
+
+	for (int i = 0; i < NCH; i ++) {
+		int size = m_hitsPerCycle[i].size();
+		int nPoint = size / 10;
+		if (size % 10)
+			nPoint ++;
+		if (nPoint == 0)
+			nPoint = 1;
+		double nHits = 0;
+		double time = 0;
+		for (int j = 0; j < size; j += 10) {
+			nHits += m_hitsPerCycle[i].at(j);
+			time += static_cast<double>(TCYCLE);
+		}
+		TVector3 pos = m_spmtMap->getPosition(m_gcuId, i);
+		m_rateDis->SetPoint(m_nPoint, pos.X() / 1000., pos.Y() / 1000., nHits / time);
+		m_nPoint ++;
+	}
+
+	m_canvas->Clear();
+
+	m_rateDis->SetTitle(";X / m;Y / m");
+	m_rateDis->SetMarkerStyle(22);
+	m_rateDis->SetMarkerSize(6.0);
+
+	m_canvas->SetLeftMargin(0.15);
+	m_canvas->SetBottomMargin(0.15);
+	m_canvas->SetTheta(90);
+	m_canvas->SetPhi(0.001);
+	m_canvas->cd();
+	m_rateDis->DrawClone("PCOL");
+	m_canvas->SaveAs(m_outPdf);
+
+	reset();
+	return true;
+}
diff --git a/Analysis/HitRateDisAnaTool/src/HitRateDisAnaTool.h b/Analysis/HitRateDisAnaTool/src/HitRateDisAnaTool.h
new file mode 100644
index 0000000..f8e9878
--- /dev/null
+++ b/Analysis/HitRateDisAnaTool/src/HitRateDisAnaTool.h
@@ -0,0 +1,83 @@
+#ifndef HitRateDisAnaTool_h
+#define HitRateDisAnaTool_h
+
+#include "AnaTool/Params.h"
+#include "AnaTool/AnaTool.h"
+#include "SniperKernel/ToolBase.h"
+#include "SniperKernel/ToolFactory.h"
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <memory>
+#include <string>
+
+#include <TH1F.h>
+#include <TH2F.h>
+#include <TCanvas.h>
+#include <TF1.h>
+#include <TString.h>
+#include <TVector3.h>
+#include <TGraph.h>
+#include <TGraph2D.h>
+#include <TGraphErrors.h>
+
+#define CYCLE 67108864
+#define TCYCLE 1.6777216
+
+using namespace std;
+
+class HitRateDisAnaTool : public AnaTool, public ToolBase {
+	public:
+		HitRateDisAnaTool(const string &name);
+		~HitRateDisAnaTool();
+
+		bool configure(string, SPMTMap*);
+		bool analyze(const Params&);
+		bool output();
+
+	private:
+		string m_outDir;
+		TString m_outPdf;
+		TString m_outTxt;
+
+		unique_ptr<TCanvas> m_canvas;
+
+		int m_gcuId;
+		int m_runNum;
+		int m_evtType;
+		int m_abcCh;
+		int m_coarseTime;
+		int m_fineTime;
+		int m_nCycle;
+		int m_lastNCycle;
+		int m_gCycle;
+		int m_gLastCT;
+		int m_lastCoarseTimes[NCH];
+		int m_cycle[NCH];
+		int m_hits[NCH];
+
+		int m_stTime[NCH];
+		int m_edTime[NCH];
+
+		int m_hrFlag;
+		int m_nPoint;
+
+		unique_ptr<TH1F> m_hitsPerCh;
+		unique_ptr<TH1F> m_timePerCh;
+
+		vector<unique_ptr<TGraphErrors>> m_rateCh;
+		unique_ptr<TGraph2D> m_rateDis;
+
+		vector<int> m_hitsPerCycle[NCH];
+		vector<double> m_catiHitsPerCyc[8];
+		vector<double> m_catiTimePerCyc[8];
+		vector<double> m_catiErroPerCyc[8];
+		vector<double> m_timePerCyc[NCH];
+
+		SPMTMap *m_spmtMap;
+
+		bool reset();
+};
+
+#endif
diff --git a/README.md b/README.md
index f2e991e..50ec59c 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,42 @@ Similar to JUNO Offline, two main structures exist: one is named **`algorithm`**
 1. **`algorithm`** can accept the input **arguments** and input **data** (only `ROOT` data can be accepted now). The **data** is input as a list written in a text file, **arguments** can be delivered to the **`algorithm`** by setting in the python script. Besides, the **`algorithm`** can call analysis **`tool`** to process the data.
 2. **`tool`** contains the true analysis algorithm
 
+## How to use existing method
+
+```bash
+source setup.sh // in the spmtOffline folder
+```
+
+### Convert binary to ROOT
+```bash
+python $SHAREROOT/convert.py --input [path of binary file list] --output [output path]
+```
+
+### Get charge spectrum
+```bash
+python $SHAREROOT/getChargeSpec.py --input [path of ROOT file list] --output [output path]
+```
+
+### Get hit rate
+```bash
+python $SHAREROOT/getHitRate.py --input [path of ROOT file list] --output [output path]
+```
+
+### Get hit rate distribution in xoy
+```bash
+python $SHAREROOT/getHitRateDis.py --input [path of ROOT file list] --output [output path]
+```
+
+### Get time interval
+```bash
+python $SHAREROOT/getTimeInterval.py --input [path of ROOT file list] --output [output path]
+```
+
+### Get noise per channel
+```bash
+python $SHAREROOT/getNoise.py --input [path of ROOT file list] --output [output path]
+```
+
 ## Create your own algorithm
 
 Create an **`algorithm`** named `ExampleAlg` in `./Analysis`
diff --git a/share/getHitRateDis.py b/share/getHitRateDis.py
new file mode 100644
index 0000000..7f1a106
--- /dev/null
+++ b/share/getHitRateDis.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+#-*- coding: utf-8 -*-
+
+# For NoiseAnaTool
+from __future__ import print_function
+
+import argparse
+import sys
+import os
+
+def get_parser():
+	parser = argparse.ArgumentParser(description='Commissioning analysis')
+	parser.add_argument("--input", default="./testList", help="the file which contains input file names")
+	parser.add_argument("--output", default="./", help="output file name")
+	parser.add_argument("--highRate", type=int, default=1)
+	parser.add_argument("--evtmax", type=int, default=-1)
+	parser.add_argument("--toollist", default="{}/hitRateDisToolList".format(os.environ.get('SHAREROOT')))
+	parser.add_argument("--gcu2pos", default="{}/gcu2pos".format(os.environ.get('SHAREROOT')))
+	parser.add_argument("--abc2cnt", default="{}/abc2cnt".format(os.environ.get('SHAREROOT')))
+	return parser
+
+parser = get_parser();
+args = parser.parse_args()
+
+import Sniper
+import CommissioningAlg
+
+# Initial task and algorithm
+# ========================================
+task = Sniper.TopTask("spmtAna")
+alg = task.createAlg("CommissioningAlg")
+
+# ========================================
+# Add new tool here
+import HitRateDisAnaTool
+
+# Add new tool here
+htTool = alg.createTool("HitRateDisAnaTool")
+
+# Set arguments
+# ========================================
+alg.property("inputList").set(args.input)
+alg.property("outputDir").set(args.output)
+alg.property("evtMax").set(args.evtmax)
+alg.property("toolNameList").set(args.toollist)
+alg.property("mapGcu2Pos").set(args.gcu2pos)
+alg.property("mapAbc2Cnt").set(args.abc2cnt)
+
+htTool.property("HighRate").set(args.highRate)
+
+task.setLogLevel(0)
+task.setEvtMax(1)
+task.run()
diff --git a/share/getNoise.py b/share/getNoise.py
new file mode 100644
index 0000000..904c40a
--- /dev/null
+++ b/share/getNoise.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#-*- coding: utf-8 -*-
+
+# For NoiseAnaTool
+from __future__ import print_function
+
+import argparse
+import sys
+import os
+
+def get_parser():
+	parser = argparse.ArgumentParser(description='Commissioning analysis')
+	parser.add_argument("--input", default="./testList", help="the file which contains input file names")
+	parser.add_argument("--output", default="./", help="output file name")
+	parser.add_argument("--evtmax", type=int, default=-1)
+	parser.add_argument("--toollist", default="{}/noiseToolList".format(os.environ.get('SHAREROOT')))
+	return parser
+
+parser = get_parser();
+args = parser.parse_args()
+
+import Sniper
+import CommissioningAlg
+
+# Initial task and algorithm
+# ========================================
+task = Sniper.TopTask("spmtAna")
+alg = task.createAlg("CommissioningAlg")
+
+# ========================================
+# Add new tool here
+import NoiseAnaTool
+
+# Add new tool here
+alg.createTool("NoiseAnaTool")
+
+# Set arguments
+# ========================================
+alg.property("inputList").set(args.input)
+alg.property("outputDir").set(args.output)
+alg.property("evtMax").set(args.evtmax)
+alg.property("toolNameList").set(args.toollist)
+
+task.setLogLevel(0)
+task.setEvtMax(1)
+task.run()
diff --git a/share/hitRateDisToolList b/share/hitRateDisToolList
new file mode 100644
index 0000000..d95ab17
--- /dev/null
+++ b/share/hitRateDisToolList
@@ -0,0 +1 @@
+HitRateDisAnaTool
diff --git a/share/noiseToolList b/share/noiseToolList
new file mode 100644
index 0000000..d77b07e
--- /dev/null
+++ b/share/noiseToolList
@@ -0,0 +1 @@
+NoiseAnaTool
-- 
GitLab