REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestDetectorSingleChannelAnalysisProcess.cxx
1
16
17#include "TRestDetectorSingleChannelAnalysisProcess.h"
18
19#include <TFitResult.h>
20#include <TLatex.h>
21#include <TLegend.h>
22#include <TLine.h>
23#include <TPaveText.h>
24#include <TRandom.h>
25#include <TSpectrum.h>
26
27using namespace std;
28
30
31TRestDetectorSingleChannelAnalysisProcess::TRestDetectorSingleChannelAnalysisProcess() { Initialize(); }
32
33TRestDetectorSingleChannelAnalysisProcess::~TRestDetectorSingleChannelAnalysisProcess() {}
34
36 SetSectionName(this->ClassName());
37 SetLibraryVersion(LIBRARY_VERSION);
38
39 fSignalEvent = nullptr;
40
41 fReadout = nullptr;
42}
43
45 fReadout = GetMetadata<TRestDetectorReadout>();
46 fCalib = GetMetadata<TRestDetectorGainMap>();
47 if (fReadout == nullptr) {
48 } else {
49 for (int i = 0; i < fReadout->GetNumberOfReadoutPlanes(); i++) {
50 auto plane = fReadout->GetReadoutPlane(i);
51 for (size_t j = 0; j < plane->GetNumberOfModules(); j++) {
52 auto mod = plane->GetModule(j);
53 for (size_t k = 0; k < mod->GetNumberOfChannels(); k++) {
54 auto channel = mod->GetChannel(k);
55 fChannelGain[channel->GetDaqID()] = 1; // default correction factor is 1
56 fChannelGainError[channel->GetDaqID()] = 1; // relative error
57 fChannelThrIntegral[channel->GetDaqID()] =
58 new TH1D(Form("h%i", channel->GetDaqID()), Form("h%i", channel->GetDaqID()), 100, 0,
59 fSpecFitRange.Y() * 1.5);
60 }
61 }
62 }
63 }
64
65 if (fApplyGainCorrection) {
66 if (fCalib != nullptr) {
67 for (auto iter = fChannelGain.begin(); iter != fChannelGain.end(); iter++) {
68 if (fCalib->fChannelGain.count(iter->first) == 0) {
69 RESTError << "in consistent gain mapping and readout definition!" << RESTendl;
70 RESTError << "channel: " << iter->first << " not fount in mapping file!" << RESTendl;
71 abort();
72 }
73 }
74
75 } else {
76 RESTError << "You must set a TRestDetectorGainMap metadata object to apply gain correction!"
77 << RESTendl;
78 abort();
79 }
80 }
81
82 if (GetFriend("TRestRawSignalAnalysisProcess") == nullptr) {
83 RESTError << "please add friend process TRestRawSignalAnalysisProcess and "
84 "TRestRawReadoutAnalysisProcess "
85 "and turn on all their observables!"
86 << RESTendl;
87 abort();
88 }
89}
90
92 fSignalEvent = (TRestDetectorSignalEvent*)inputEvent;
93
94 Double_t new_PeakAmplitudeIntegral = 0;
95 Double_t new_ThresholdIntegral = 0;
96
97 map<int, Double_t> sAna_max_amplitude_map = GetObservableValue<map<int, Double_t>>("max_amplitude_map");
98 map<int, Double_t> sAna_thr_integral_map = GetObservableValue<map<int, Double_t>>("thr_integral_map");
99 Double_t sAna_ThresholdIntegral = GetObservableValue<Double_t>("ThresholdIntegral");
100 Double_t sAna_NumberOfGoodSignals = GetObservableValue<int>("NumberOfGoodSignals");
101
102 if (fCreateGainMap) {
103 if ((sAna_ThresholdIntegral > fThrIntegralCutRange.X() &&
104 sAna_ThresholdIntegral < fThrIntegralCutRange.Y()) &&
105 (sAna_NumberOfGoodSignals > fNGoodSignalsCutRange.X() &&
106 sAna_NumberOfGoodSignals < fNGoodSignalsCutRange.Y())) {
107 // if within energy cut range
108
109 for (auto iter = sAna_thr_integral_map.begin(); iter != sAna_thr_integral_map.end(); iter++) {
110 if (fChannelThrIntegral[iter->first] == nullptr) {
111 fChannelThrIntegral[iter->first] = new TH1D(
112 Form("h%i", iter->first), Form("h%i", iter->first), 100, 0, fSpecFitRange.Y() * 1.5);
113 }
114
115 fChannelThrIntegral[iter->first]->Fill(iter->second);
116 }
117 }
118 }
119
120 else if (fApplyGainCorrection) {
121 // calculate updated ThresholdIntegral and PeakAmplitudeIntegral applying correction map
122 for (auto iter = sAna_max_amplitude_map.begin(); iter != sAna_max_amplitude_map.end(); iter++) {
123 if (fCalib->fChannelGain.count(iter->first)) {
124 iter->second *= fCalib->fChannelGain[iter->first];
125 }
126 new_PeakAmplitudeIntegral += iter->second;
127 }
128
129 for (auto iter = sAna_thr_integral_map.begin(); iter != sAna_thr_integral_map.end(); iter++) {
130 if (fCalib->fChannelGain.count(iter->first)) {
131 iter->second *= fCalib->fChannelGain[iter->first];
132 }
133 new_ThresholdIntegral += iter->second;
134 }
135
136 // update charge value in output event
137 for (int i = 0; i < fSignalEvent->GetNumberOfSignals(); i++) {
138 TRestDetectorSignal* sgn = fSignalEvent->GetSignal(i);
139 if (fCalib->fChannelGain.count(sgn->GetID()) == 0 || fCalib->fChannelGain[sgn->GetID()] == 0) {
140 cout << "warning! unrecorded gain for channel: " << sgn->GetID() << endl;
141 continue;
142 }
143 double gain = fCalib->fChannelGain[sgn->GetID()];
144 for (int j = 0; j < sgn->GetNumberOfPoints(); j++) {
145 auto timecharge = sgn->GetPoint(j);
146 sgn->SetPoint(j, timecharge.X(), timecharge.Y() * gain);
147 }
148 }
149 }
150
151 SetObservableValue("ChnCorr_AmpInt", new_PeakAmplitudeIntegral);
152 SetObservableValue("ChnCorr_ThrInt", new_ThresholdIntegral);
153
154 return fSignalEvent;
155}
156
158 if (fCreateGainMap) {
159 FitChannelGain();
160 // SaveGainMetadata(fCalibSave);
161 }
162}
163
164void TRestDetectorSingleChannelAnalysisProcess::FitChannelGain() {
165 cout << "TRestDetectorSingleChannelAnalysisProcess: fitting channel gain..." << endl;
166
167 double channelFitMeanSum = 0;
168
169 for (auto iter = fChannelThrIntegral.begin(); iter != fChannelThrIntegral.end(); iter++) {
170 TH1D* h = iter->second;
171 if (h->GetEntries() > 100) {
172 // direct fit
173 double middle = (fSpecFitRange.X() + fSpecFitRange.Y()) / 2;
174 double range = (fSpecFitRange.Y() - fSpecFitRange.X()) / 2;
175 TFitResultPtr r = h->Fit("gaus", "QS", "", fSpecFitRange.X(), fSpecFitRange.Y());
176 if (r != -1) {
177 const double* results = r->GetParams();
178 double mean = results[1];
179 double sigma = results[2];
180
181 if (mean > middle - range / 1.2 && mean < middle + range / 1.2 && sigma / mean < 0.5) {
182 fChannelFitMean[iter->first] = mean;
183 channelFitMeanSum += mean;
184 fChannelGainError[iter->first] = sigma / mean;
185 cout << iter->first << ", mean: " << mean << ", error: " << sigma / mean << endl;
186 continue;
187 }
188 }
189
190 // if fit with gaus failed, we use TSpectrum to find the peak
191 TSpectrum spc;
192 int n = spc.Search(h);
193 double* peaks = spc.GetPositionX();
194 double min = std::numeric_limits<Double_t>::max();
195 int minpos = 0;
196 for (int i = 0; i < n; i++) {
197 double dist = abs(peaks[i] - middle);
198 if (dist < min) {
199 min = dist;
200 minpos = i;
201 }
202 }
203 if (min < range * 2) {
204 fChannelFitMean[iter->first] = peaks[minpos];
205 channelFitMeanSum += peaks[minpos];
206 fChannelGainError[iter->first] = 1;
207 cout << iter->first << ", peak position: " << peaks[minpos] << ", total peaks: " << n << endl;
208 continue;
209 }
210
211 // it is very bad channel, we prompt a warning
212 cout << iter->first << ", too bad to fit" << endl;
213 }
214 }
215
216 double meanmean = channelFitMeanSum / fChannelFitMean.size();
217
218 cout << meanmean << endl;
219
220 // normalize and fill the result
221 for (auto iter = fChannelGain.begin(); iter != fChannelGain.end(); iter++) {
222 if (fChannelFitMean.count(iter->first) == 0) {
223 iter->second = 1;
224 } else {
225 iter->second = meanmean / fChannelFitMean[iter->first];
226 }
227 }
228}
229
230/*** This should not be done. The framework saves any metadata structure inside of the
231 * common TRestRun during processing. If TRestRun does not know a particular metadata
232 * instance, then it should be added to the run, and it will be written to disk with it.
233 * If we want just to have a method to export data, in principe it is possible. But
234 * better without using a new TRestRun instance. TRestRun should only be created for
235 * writing the standard processing scheme.
236 ***/
237void TRestDetectorSingleChannelAnalysisProcess::SaveGainMetadata(string filename) {
238 cout << "TRestDetectorSingleChannelAnalysisProcess: saving result..." << endl;
239
240 // for (auto iter = fChannelGain.begin(); iter != fChannelGain.end(); iter++) {
241 // cout << iter->first << " " << iter->second << endl;
242 //}
243
244 fCalib = new TRestDetectorGainMap();
245 fCalib->fChannelGain = fChannelGain;
246 fCalib->SetName("ChannelCalibration");
247
248 TRestRun* r = (TRestRun*)fRunInfo->Clone();
249 r->SetOutputFileName(filename);
250 r->AddMetadata(fCalib);
251 r->AddMetadata(fReadout);
252 r->AddMetadata(this);
253 r->FormOutputFile();
254
255 PrintChannelSpectrums(filename);
256 delete r;
257}
258
259TH1D* TRestDetectorSingleChannelAnalysisProcess::GetChannelSpectrum(int id) {
260 if (fChannelThrIntegral.count(id) != 0) return fChannelThrIntegral[id];
261 return nullptr;
262}
263
264void TRestDetectorSingleChannelAnalysisProcess::PrintChannelSpectrums(string filename) {
265 TCanvas* c = new TCanvas();
266 TLatex pText;
267 pText.SetTextColor(kBlack);
268 pText.SetTextFont(132);
269 pText.SetTextSize(0.05);
270 TLine pLine;
271 pLine.SetLineColor(1);
272 pLine.SetLineWidth(1);
273 pLine.SetLineColor(1);
274
275 c->Print((filename + ".pdf[").c_str());
276 for (auto iter = fChannelThrIntegral.begin(); iter != fChannelThrIntegral.end(); iter++) {
277 if (iter->second != nullptr && iter->second->GetEntries() > 0) {
278 cout << "Drawing: " << iter->first << endl;
279 c->Clear();
280 iter->second->Draw();
281 pText.DrawLatex(fChannelFitMean[iter->first], iter->second->GetMaximum(),
282 Form("Relative gain: %.3f", fChannelGain[iter->first]));
283 pText.DrawLatex(fChannelFitMean[iter->first], iter->second->GetMaximum() * 0.9,
284 Form("Error: %.2f", fChannelGainError[iter->first]));
285 pLine.DrawLine(fChannelFitMean[iter->first], 0, fChannelFitMean[iter->first],
286 iter->second->GetMaximum() * 0.9);
287 c->Print((filename + ".pdf").c_str());
288 }
289 }
290 c->Clear();
291 c->Print((filename + ".pdf]").c_str());
292 delete c;
293}
294
295// setting amplification:
296// <parameter name="modulesAmp" value = "2-1:5-1.2:6-0.8:8-0.9" />
297// setting readout modules to draw:
298// <parameter name="modulesHist" value="2:5:6:8"/>
300 string mode = GetParameter("mode", "apply");
301 if (mode == "create") {
302 fCreateGainMap = true;
303 fApplyGainCorrection = false;
304 fSingleThreadOnly = true;
305 } else if (mode == "apply") {
306 fCreateGainMap = false;
307 fApplyGainCorrection = true;
308 fSingleThreadOnly = false;
309 } else {
310 RESTError << "illegal mode definition! supported: create, apply" << RESTendl;
311 abort();
312 }
313
314 fThrIntegralCutRange = StringTo2DVector(GetParameter("thrEnergyRange", "(0,1e9)"));
315 fNGoodSignalsCutRange = StringTo2DVector(GetParameter("nGoodSignalsRange", "(4,14)"));
316 fSpecFitRange = StringTo2DVector(GetParameter("specFitRange", "(1e4,2e4)"));
317 fCalibSave = GetParameter("save", "calib.root");
318}
TRestDetectorReadoutChannel * GetChannel(size_t n)
Returns a pointer to a readout channel by index.
TRestDetectorReadoutModule * GetModule(size_t mod)
Returns a pointer to a readout module using its std::vector index.
TRestDetectorReadoutPlane * GetReadoutPlane(int p)
Returns a pointer to the readout plane by index.
void SetPoint(const TVector2 &p)
If the point already exists inside the detector signal event, it will be overwritten....
TRestEvent * ProcessEvent(TRestEvent *inputEvent) override
Process one event.
void EndProcess() override
To be executed at the end of the run (outside event loop)
void InitProcess() override
To be executed at the beginning of the run (outside event loop)
void InitFromConfigFile() override
To make settings from rml file. This method must be implemented in the derived class.
TRestRun * fRunInfo
< Pointer to TRestRun object where to find metadata.
void SetObservableValue(const std::string &name, const T &value)
Set observable value for AnalysisTree.
A base class for any REST event.
Definition: TRestEvent.h:38
endl_t RESTendl
Termination flag object for TRestStringOutput.
void SetLibraryVersion(TString version)
Set the library version of this metadata class.
void SetSectionName(std::string sName)
set the section name, clear the section content
std::string GetParameter(std::string parName, TiXmlElement *e, TString defaultValue=PARAMETER_NOT_FOUND_STR)
Returns the value for the parameter named parName in the given section.
Data provider and manager in REST.
Definition: TRestRun.h:18
TFile * FormOutputFile()
Create a new TFile as REST output file. Writing metadata objects into it.
Definition: TRestRun.cxx:1036
void AddMetadata(TRestMetadata *meta)
add metadata object to the metadata list
Definition: TRestRun.h:112
TVector2 StringTo2DVector(std::string in)
Gets a 2D-vector from a string.