Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ViewSignal.cc
Go to the documentation of this file.
1#include <TAxis.h>
2#include <TGraph.h>
3
4#include <iostream>
5
9#include "Garfield/Sensor.hh"
10#include "TLegend.h"
11#include "TPaveLabel.h"
12
13namespace Garfield {
14
15ViewSignal::ViewSignal() : ViewBase("ViewSignal") {}
16
18 if (!s) {
19 std::cerr << m_className << "::SetSensor: Null pointer.\n";
20 return;
21 }
22 m_sensor = s;
23}
24
25void ViewSignal::SetRangeX(const double xmin, const double xmax) {
26 if (fabs(xmax - xmin) < Small) {
27 std::cerr << m_className << "::SetRangeX: Invalid range.\n";
28 return;
29 }
30 m_xmin = std::min(xmin, xmax);
31 m_xmax = std::max(xmin, xmax);
32 m_userRangeX = true;
33}
34
35void ViewSignal::SetRangeY(const double ymin, const double ymax) {
36 if (fabs(ymax - ymin) < Small) {
37 std::cerr << m_className << "::SetRangeY: Invalid range.\n";
38 return;
39 }
40 m_ymin = std::min(ymin, ymax);
41 m_ymax = std::max(ymin, ymax);
42 m_userRangeY = true;
43}
44
45void ViewSignal::PlotSignal(const std::string& label, const bool total,
46 const bool electron, const bool ion,
47 const bool delayed, const bool same) {
48 if (!m_sensor) {
49 std::cerr << m_className << "::PlotSignal: Sensor is not defined.\n";
50 return;
51 }
52
53 auto canvas = GetCanvas();
54 canvas->cd();
55 canvas->SetTitle("Signal");
56
57 unsigned int nBins = 100;
58 double t0 = 0., dt = 1.;
59 m_sensor->GetTimeWindow(t0, dt, nBins);
60 const double t1 = t0 + nBins * dt;
61
62 std::string xlabel = "time [ns]";
63 std::string ylabel = m_labelY;
64 if (ylabel.empty()) {
65 ylabel = m_sensor->IsIntegrated(label) ? "signal [fC]" : "signal [fC / ns]";
66 }
67 unsigned int nPlots = same ? 1 : 0;
68 if (total) {
69 const auto hname = FindUnusedHistogramName("hSignal_");
70 m_hSignal.reset(new TH1D(hname.c_str(), "", nBins, t0, t1));
71 m_hSignal->SetLineColor(m_colTotal);
72 m_hSignal->GetXaxis()->SetTitle(xlabel.c_str());
73 m_hSignal->GetYaxis()->SetTitle(ylabel.c_str());
74 m_hSignal->SetStats(0);
75 for (unsigned int i = 0; i < nBins; ++i) {
76 const double sig = m_sensor->GetSignal(label, i);
77 m_hSignal->SetBinContent(i + 1, sig);
78 }
79 const std::string opt = nPlots > 0 ? "same" : "";
80 m_hSignal->DrawCopy(opt.c_str());
81 ++nPlots;
82 if (m_userRangeX) m_hSignal->SetAxisRange(m_xmin, m_xmax, "X");
83 if (m_userRangeY) m_hSignal->SetAxisRange(m_ymin, m_ymax, "Y");
84
85 // Get and plot threshold crossings.
86 const auto nCrossings = m_sensor->GetNumberOfThresholdCrossings();
87 if (nCrossings > 0) {
88 TGraph gCrossings;
89 gCrossings.SetMarkerStyle(20);
90 gCrossings.SetMarkerColor(m_colTotal);
91 std::vector<double> xp;
92 std::vector<double> yp;
93 double time = 0., level = 0.;
94 bool rise = true;
95 for (unsigned int i = 0; i < nCrossings; ++i) {
96 if (m_sensor->GetThresholdCrossing(i, time, level, rise)) {
97 xp.push_back(time);
98 yp.push_back(level);
99 }
100 }
101 gCrossings.DrawGraph(xp.size(), xp.data(), yp.data(), "psame");
102 }
103
104 if (delayed) {
105 const auto hnamed = FindUnusedHistogramName("hDelayedSignal_");
106 m_hDelayedSignal.reset(new TH1D(hnamed.c_str(), "", nBins, t0, t1));
107 m_hDelayedSignal->SetLineColor(m_colDelayed[0]);
108 m_hDelayedSignal->SetLineStyle(2);
109 m_hDelayedSignal->SetStats(0);
110 for (unsigned int i = 0; i < nBins; ++i) {
111 const double sig = m_sensor->GetDelayedElectronSignal(label, i) +
112 m_sensor->GetDelayedIonSignal(label, i);
113 m_hDelayedSignal->SetBinContent(i + 1, sig);
114 }
115 m_hDelayedSignal->DrawCopy("same");
116 }
117 gPad->Update();
118 }
119
120 // Plot the electron and ion signals if requested.
121 if (electron) {
122 const auto hname = FindUnusedHistogramName("hSignalElectrons_");
123 m_hSignalElectrons.reset(new TH1D(hname.c_str(), "", nBins, t0, t1));
124 m_hSignalElectrons->SetLineColor(m_colElectrons);
125 m_hSignalElectrons->GetXaxis()->SetTitle(xlabel.c_str());
126 m_hSignalElectrons->GetYaxis()->SetTitle(ylabel.c_str());
127 m_hSignalElectrons->SetStats(0);
128 for (unsigned int i = 0; i < nBins; ++i) {
129 const double sig = m_sensor->GetElectronSignal(label, i);
130 m_hSignalElectrons->SetBinContent(i + 1, sig);
131 }
132 const std::string opt = nPlots > 0 ? "same" : "";
133 m_hSignalElectrons->DrawCopy(opt.c_str());
134 ++nPlots;
135 if (!total) {
136 if (m_userRangeX) m_hSignalElectrons->SetAxisRange(m_xmin, m_xmax, "X");
137 if (m_userRangeY) m_hSignalElectrons->SetAxisRange(m_ymin, m_ymax, "Y");
138 }
139 if (delayed) {
140 const auto hnamed = FindUnusedHistogramName("hDelayedSignalElectrons_");
141 m_hDelayedSignalElectrons.reset(new TH1D(hnamed.c_str(), "", nBins, t0, t1));
142 m_hDelayedSignalElectrons->SetLineColor(m_colDelayed[1]);
143 m_hDelayedSignalElectrons->SetLineStyle(2);
144 m_hDelayedSignalElectrons->SetStats(0);
145 for (unsigned int i = 0; i < nBins; ++i) {
146 const double sig = m_sensor->GetDelayedElectronSignal(label, i);
147 m_hDelayedSignalElectrons->SetBinContent(i + 1, sig);
148 }
149 m_hDelayedSignalElectrons->DrawCopy("same");
150 }
151 gPad->Update();
152 }
153 if (ion) {
154 const auto hname = FindUnusedHistogramName("hSignalIons_");
155 m_hSignalIons.reset(new TH1D(hname.c_str(), "", nBins, t0, t1));
156 m_hSignalIons->SetLineColor(m_colIons);
157 m_hSignalIons->GetXaxis()->SetTitle(xlabel.c_str());
158 m_hSignalIons->GetYaxis()->SetTitle(ylabel.c_str());
159 m_hSignalIons->SetStats(0);
160 for (unsigned int i = 0; i < nBins; ++i) {
161 const double sig = m_sensor->GetIonSignal(label, i);
162 m_hSignalIons->SetBinContent(i + 1, sig);
163 }
164 const std::string opt = nPlots > 0 ? "same" : "";
165 m_hSignalIons->DrawCopy(opt.c_str());
166 ++nPlots;
167 if (!(total || electron)) {
168 if (m_userRangeX) m_hSignalIons->SetAxisRange(m_xmin, m_xmax, "X");
169 if (m_userRangeY) m_hSignalIons->SetAxisRange(m_ymin, m_ymax, "Y");
170 }
171 if (delayed) {
172 const auto hnamed = FindUnusedHistogramName("hDelayedSignalIons_");
173 m_hDelayedSignalIons.reset(new TH1D(hnamed.c_str(), "", nBins, t0, t1));
174 m_hDelayedSignalIons->SetLineColor(m_colDelayed[2]);
175 m_hDelayedSignalIons->SetLineStyle(2);
176 m_hDelayedSignalIons->SetStats(0);
177 for (unsigned int i = 0; i < nBins; ++i) {
178 const double sig = m_sensor->GetDelayedIonSignal(label, i);
179 m_hDelayedSignalIons->SetBinContent(i + 1, sig);
180 }
181 m_hDelayedSignalIons->DrawCopy("same");
182 }
183 gPad->Update();
184 }
185}
186
187void ViewSignal::Plot(const std::string &label, const bool getsignal,
188 const bool total, const bool delayed, const bool same) {
189 // When plotting the induced charge, integrate the signal.
190 if (!getsignal) m_sensor->IntegrateSignal(label);
191 // Check if sensor is defined.
192 if (!m_sensor) {
193 std::cerr << m_className << "::PlotSignal: Sensor is not defined.\n";
194 return;
195 }
196 const double pres = 1e-50;
197 // Create canvas
198 auto canvas = GetCanvas();
199 canvas->cd();
200 canvas->SetTitle("Signal");
201 // Get the time window from the sensor class
202 unsigned int nBins = 100;
203 double t0 = 0., dt = 1.;
204 m_sensor->GetTimeWindow(t0, dt, nBins);
205 const double t1 = t0 + nBins * dt;
206 // Axis labels
207 std::string xlabel = "time [ns]";
208 std::string ylabel = m_labelY;
209 if (ylabel.empty()) {
210 ylabel = getsignal ? "signal [fC / ns]" : "charge [fC]";
211 }
212 // This plot will contain three seperate histograms: prompt, delayed and total
213 // signal/charge.
214 unsigned int nPlots = same ? 1 : 0;
215 if (total) {
216 // Makign the total signal/charge histogram.
217 const auto hname = FindUnusedHistogramName("hSignal_");
218 m_hSignal.reset(new TH1D(hname.c_str(), "", nBins, t0, t1));
219 m_hSignal->SetLineColor(m_colTotal);
220 // Set histogram axis labels
221 m_hSignal->GetXaxis()->SetTitle(xlabel.c_str());
222 m_hSignal->GetYaxis()->SetTitle(ylabel.c_str());
223 m_hSignal->SetStats(0);
224 // Fill histogram with total signal
225 for (unsigned int i = 0; i < nBins; ++i) {
226 const double sig = m_sensor->GetSignal(label, i, 0);
227 if(!std::isnan(sig) && std::abs(sig) < pres) {
228 m_hSignal->SetBinContent(i + 1, 0.);
229 } else {
230 m_hSignal->SetBinContent(i + 1, sig);
231 }
232 }
233 m_hSignal->SetLineWidth(6);
234 const std::string opt = nPlots > 0 ? "same" : "";
235 m_hSignal->DrawCopy(opt.c_str());
236 ++nPlots;
237 if (m_userRangeX) m_hSignal->SetAxisRange(m_xmin, m_xmax, "X");
238 if (m_userRangeY) m_hSignal->SetAxisRange(m_ymin, m_ymax, "Y");
239 // Get and plot threshold crossings.
240 const auto nCrossings = m_sensor->GetNumberOfThresholdCrossings();
241 if (nCrossings > 0) {
242 TGraph gCrossings;
243 gCrossings.SetMarkerStyle(20);
244 gCrossings.SetMarkerColor(m_colTotal);
245 std::vector<double> xp;
246 std::vector<double> yp;
247 double time = 0., level = 0.;
248 bool rise = true;
249 for (unsigned int i = 0; i < nCrossings; ++i) {
250 if (m_sensor->GetThresholdCrossing(i, time, level, rise)) {
251 xp.push_back(time);
252 yp.push_back(level);
253 }
254 }
255 gCrossings.DrawGraph(xp.size(), xp.data(), yp.data(), "psame");
256 }
257 if (delayed) {
258 // Making the delayed component histogram.
259 const auto hnamed = FindUnusedHistogramName("hDelayedCharge_");
260 m_hDelayedSignal.reset(new TH1D(hnamed.c_str(), "", nBins, t0, t1));
261 m_hDelayedSignal->SetLineColor(m_colDelayed[0]);
262 m_hDelayedSignal->SetLineStyle(2);
263 m_hDelayedSignal->SetStats(0);
264 for (unsigned int i = 0; i < nBins; ++i) {
265 const double sig = m_sensor->GetSignal(label, i, 2);
266 if (!std::isnan(sig) && std::abs(sig) < pres) {
267 m_hDelayedSignal->SetBinContent(i + 1, 0.);
268 } else {
269 m_hDelayedSignal->SetBinContent(i + 1, sig);
270 }
271 }
272 m_hDelayedSignal->SetFillStyle(3001);
273 m_hDelayedSignal->SetFillColor(m_colDelayed[0]);
274 }
275 // Making the prompt component histogram.
276 const auto dnamed = FindUnusedHistogramName("hPromptCharge_");
277 m_hPromptSignal.reset(new TH1D(dnamed.c_str(), "", nBins, t0, t1));
278 m_hPromptSignal->SetLineColor(m_colDelayed[2]);
279 m_hPromptSignal->SetLineStyle(2);
280 m_hPromptSignal->SetStats(0);
281 for (unsigned int i = 0; i < nBins; ++i) {
282 const double sig = m_sensor->GetSignal(label, i, 1);
283 if (!std::isnan(sig) && std::abs(sig) < pres) {
284 m_hPromptSignal->SetBinContent(i + 1, 0.);
285 } else {
286 m_hPromptSignal->SetBinContent(i + 1, sig);
287 }
288 }
289 m_hPromptSignal->SetFillStyle(3001);
290 m_hPromptSignal->SetFillColor(m_colDelayed[2]);
291 m_hPromptSignal->DrawCopy("same");
292 if (delayed) m_hDelayedSignal->DrawCopy("same");
293
294 TPaveLabel *label1 = new TPaveLabel(-3.5, 700, -1, 800, "Default option");
295 label1->Draw();
296 // Coloring the bins.
297 TH1D *g0 = new TH1D("g0", "g0", nBins, 0, 1);
298 g0->SetFillColor(m_colTotal);
299 TH1D *g1 = new TH1D("g1", "g1", nBins, 0, 1);
300 g1->SetFillStyle(3001);
301 g1->SetFillColor(m_colDelayed[0]);
302
303 TH1D *g2 = new TH1D("g2", "g2", nBins, 0, 1);
304 g2->SetFillStyle(3001);
305 g2->SetFillColor(m_colDelayed[2]);
306
307 TLegend *leg = new TLegend(0.7, 0.7, 0.9, 0.9);
308 if (!getsignal) {
309 leg->SetHeader("Induced charge as a function of time");
310 leg->AddEntry(g0, "Total induced charge", "f");
311 leg->AddEntry(g2, "Prompt induced charge", "f");
312 if (delayed) leg->AddEntry(g1, "Delayed induced charge", "f");
313
314 } else {
315 leg->SetHeader("Induced current as a function of time");
316 leg->AddEntry(g0, "Total induced current", "f");
317 leg->AddEntry(g2, "Prompt induced current", "f");
318 if (delayed) leg->AddEntry(g1, "Delayed induced current", "f");
319 }
320 leg->Draw();
321 gPad->Update();
322
323 delete g0;
324 if (delayed) delete g1;
325 delete g2;
326 }
327}
328
329} // namespace Garfield
double GetElectronSignal(const std::string &label, const unsigned int bin)
Retrieve the electron signal for a given electrode and time bin.
Definition: Sensor.cc:857
double GetDelayedIonSignal(const std::string &label, const unsigned int bin)
Retrieve the delayed ion/hole signal for a given electrode and time bin.
Definition: Sensor.cc:889
void GetTimeWindow(double &tstart, double &tstep, unsigned int &nsteps) const
Retrieve the time window and binning.
Definition: Sensor.hh:96
bool IntegrateSignal(const std::string &label)
Replace the signal on a given electrode by its integral.
Definition: Sensor.cc:1244
double GetSignal(const std::string &label, const unsigned int bin)
Retrieve the total signal for a given electrode and time bin.
Definition: Sensor.cc:912
bool GetThresholdCrossing(const unsigned int i, double &time, double &level, bool &rise) const
Definition: Sensor.cc:1553
size_t GetNumberOfThresholdCrossings() const
Definition: Sensor.hh:201
double GetDelayedElectronSignal(const std::string &label, const unsigned int bin)
Retrieve the delayed electron signal for a given electrode and time bin.
Definition: Sensor.cc:878
double GetIonSignal(const std::string &label, const unsigned int bin)
Retrieve the ion or hole signal for a given electrode and time bin.
Definition: Sensor.cc:868
bool IsIntegrated(const std::string &label) const
Return whether the signal has been integrated/convoluted.
Definition: Sensor.cc:1276
Base class for visualization classes.
Definition: ViewBase.hh:18
static std::string FindUnusedHistogramName(const std::string &s)
Find an unused histogram name.
Definition: ViewBase.cc:300
std::string m_className
Definition: ViewBase.hh:78
TPad * GetCanvas()
Retrieve the canvas.
Definition: ViewBase.cc:74
ViewSignal()
Constructor.
Definition: ViewSignal.cc:15
void SetSensor(Sensor *s)
Set the sensor from which to retrieve the signal.
Definition: ViewSignal.cc:17
void SetRangeY(const double ymin, const double ymax)
Set the y-axis limits explicitly.
Definition: ViewSignal.cc:35
void SetRangeX(const double xmin, const double xmax)
Set the x-axis limits explicitly.
Definition: ViewSignal.cc:25
void PlotSignal(const std::string &label, const bool total=true, const bool electron=false, const bool ion=false, const bool delayed=false, const bool same=false)
Definition: ViewSignal.cc:45
void Plot(const std::string &label, const bool getsignal, const bool total=true, const bool delayed=true, const bool same=false)
Definition: ViewSignal.cc:187