Garfield++ 5.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ViewDrift.cc
Go to the documentation of this file.
1#include <iostream>
2#include <cmath>
3#include <algorithm>
4#include <iterator>
5#include <limits>
6
7#include <TGraph.h>
8#include <TPolyLine3D.h>
9#include <TPolyMarker3D.h>
10#include <TAxis.h>
11#include <TAxis3D.h>
12#include <TH1F.h>
13#include <TView3D.h>
14#include <TVirtualViewer3D.h>
15
16#include "Garfield/Plotting.hh"
17#include "Garfield/ViewDrift.hh"
18
19namespace Garfield {
20
22 m_driftLines.reserve(1000);
23 m_tracks.reserve(100);
24 m_exc.reserve(1000);
25 m_ion.reserve(1000);
26 m_att.reserve(1000);
27}
28
30 m_driftLines.clear();
31 m_tracks.clear();
32
33 m_exc.clear();
34 m_ion.clear();
35 m_att.clear();
36}
37
38void ViewDrift::SetClusterMarkerSize(const double size) {
39 if (size > 0.) {
40 m_markerSizeCluster = size;
41 } else {
42 std::cerr << m_className << "::SetClusterMarkerSize: Size must be > 0.\n";
43 }
44}
45
46void ViewDrift::SetCollisionMarkerSize(const double size) {
47 if (size > 0.) {
48 m_markerSizeCollision = size;
49 } else {
50 std::cerr << m_className << "::SetCollisionMarkerSize: Size must be > 0.\n";
51 }
52}
53
54void ViewDrift::GetDriftLine(const size_t i,
55 std::vector<std::array<float, 3> >& driftLine,
56 bool& electron) const {
57 driftLine.clear();
58 if (i >= m_driftLines.size()) return;
59 std::copy(m_driftLines[i].first.begin(), m_driftLines[i].first.end(),
60 std::back_inserter(driftLine));
61 if (m_driftLines[i].second == Particle::Electron) {
62 electron = true;
63 } else {
64 electron = false;
65 }
66}
67
68size_t ViewDrift::NewDriftLine(const Particle particle, const size_t np,
69 const float x0, const float y0, const float z0) {
70 std::lock_guard<std::mutex> guard(m_mutex);
71 // Create a new drift line and add it to the list.
72 std::array<float, 3> p = {x0, y0, z0};
73 constexpr size_t minSize = 1;
74 std::vector<std::array<float, 3> > dl(std::max(minSize, np), p);
75 m_driftLines.push_back(std::make_pair(std::move(dl), particle));
76 // Return the index of this drift line.
77 return m_driftLines.size() - 1;
78}
79
80void ViewDrift::AddPhoton(const float x0, const float y0, const float z0,
81 const float x1, const float y1, const float z1) {
82 std::lock_guard<std::mutex> guard(m_mutex);
83 std::array<float, 3> p0 = {x0, y0, z0};
84 std::array<float, 3> p1 = {x1, y1, z1};
85 m_photons.push_back({p0, p1});
86}
87
88void ViewDrift::NewChargedParticleTrack(const size_t np, size_t& id,
89 const float x0, const float y0,
90 const float z0) {
91 std::lock_guard<std::mutex> guard(m_mutex);
92 // Create a new track and add it to the list.
93 constexpr size_t minSize = 1;
94 std::vector<std::array<float, 3> > track(std::max(minSize, np));
95 track[0] = {x0, y0, z0};
96 m_tracks.push_back(std::move(track));
97 // Return the index of this track.
98 id = m_tracks.size() - 1;
99}
100
101void ViewDrift::SetDriftLinePoint(const size_t iL, const size_t iP,
102 const float x, const float y,
103 const float z) {
104 std::lock_guard<std::mutex> guard(m_mutex);
105 if (iL >= m_driftLines.size() || iP >= m_driftLines[iL].first.size()) {
106 std::cerr << m_className << "::SetDriftLinePoint: Index out of range.\n";
107 return;
108 }
109 m_driftLines[iL].first[iP] = {x, y, z};
110}
111
112void ViewDrift::AddDriftLinePoint(const size_t iL, const float x,
113 const float y, const float z) {
114 std::lock_guard<std::mutex> guard(m_mutex);
115 if (iL >= m_driftLines.size()) {
116 std::cerr << m_className << "::AddDriftLinePoint: Index out of range.\n";
117 return;
118 }
119 std::array<float, 3> p = {x, y, z};
120 m_driftLines[iL].first.push_back(std::move(p));
121}
122
123void ViewDrift::SetTrackPoint(const size_t iL, const size_t iP,
124 const float x, const float y, const float z) {
125 std::lock_guard<std::mutex> guard(m_mutex);
126 if (iL >= m_tracks.size() || iP >= m_tracks[iL].size()) {
127 std::cerr << m_className << "::SetTrackPoint: Index out of range.\n";
128 return;
129 }
130 m_tracks[iL][iP] = {x, y, z};
131}
132
133void ViewDrift::AddTrackPoint(const size_t iL, const float x,
134 const float y, const float z) {
135 std::lock_guard<std::mutex> guard(m_mutex);
136 if (iL >= m_tracks.size()) {
137 std::cerr << m_className << "::AddTrackPoint: Index out of range.\n";
138 return;
139 }
140 std::array<float, 3> p = {x, y, z};
141 m_tracks[iL].push_back(std::move(p));
142}
143
144void ViewDrift::AddExcitation(const float x, const float y, const float z) {
145 std::lock_guard<std::mutex> guard(m_mutex);
146 std::array<float, 3> p = {x, y, z};
147 m_exc.push_back(std::move(p));
148}
149
150void ViewDrift::AddIonisation(const float x, const float y, const float z) {
151 std::lock_guard<std::mutex> guard(m_mutex);
152 std::array<float, 3> p = {x, y, z};
153 m_ion.push_back(std::move(p));
154}
155
156void ViewDrift::AddAttachment(const float x, const float y, const float z) {
157 std::lock_guard<std::mutex> guard(m_mutex);
158 std::array<float, 3> p = {x, y, z};
159 m_att.push_back(std::move(p));
160}
161
162void ViewDrift::Plot(const bool twod, const bool axis, const bool snapshot) {
163 if (twod) {
164 Plot2d(axis, snapshot);
165 } else {
166 Plot3d(axis, false, snapshot);
167 }
168}
169
170void ViewDrift::Plot2d(const bool axis, const bool snapshot) {
171 auto pad = GetCanvas();
172 pad->cd();
173 pad->SetTitle("Drift lines");
174 // Check if the canvas range has already been set.
175 const bool rangeSet = RangeSet(pad);
176 if (axis || !rangeSet) {
177 // Determine the plot limits.
178 if (!SetPlotLimits2d()) {
179 std::cerr << m_className << "::Plot2d:\n"
180 << " Could not determine the plot limits.\n";
181 return;
182 }
183 }
184 if (axis) {
185 auto frame = pad->DrawFrame(m_xMinPlot, m_yMinPlot,
187 frame->GetXaxis()->SetTitle(LabelX().c_str());
188 frame->GetYaxis()->SetTitle(LabelY().c_str());
189 } else if (!rangeSet) {
191 }
192 if (snapshot) {
193 std::vector<std::array<float, 3> > electrons;
194 std::vector<std::array<float, 3> > holes;
195 std::vector<std::array<float, 3> > ions;
196 for (const auto& driftLine : m_driftLines) {
197 if (driftLine.second == Particle::Electron) {
198 electrons.push_back(driftLine.first.back());
199 } else if (driftLine.second == Particle::Hole) {
200 holes.push_back(driftLine.first.back());
201 } else {
202 ions.push_back(driftLine.first.back());
203 }
204 }
205 DrawMarkers2d(electrons, m_colElectron, m_markerSizeCollision);
206 DrawMarkers2d(holes, m_colHole, m_markerSizeCollision);
207 DrawMarkers2d(ions, m_colIon, m_markerSizeCollision);
208 } else {
209 for (const auto& driftLine : m_driftLines) {
210 const short lw = 1;
211 if (driftLine.second == Particle::Electron) {
212 DrawLine(driftLine.first, m_colElectron, lw);
213 } else if (driftLine.second == Particle::Hole) {
214 DrawLine(driftLine.first, m_colHole, lw);
215 } else {
216 DrawLine(driftLine.first, m_colIon, lw);
217 }
218 }
219 }
220 gPad->Update();
221
222 for (const auto& track : m_tracks) {
223 DrawLine(track, m_colTrack, 2);
224 if (!m_drawClusters) continue;
225 DrawMarkers2d(track, m_colTrack, m_markerSizeCluster);
226 }
227
228 TGraph gr;
229 gr.SetLineColor(m_colPhoton);
230 gr.SetLineStyle(2);
231 for (const auto& photon : m_photons) {
232 float xp0 = 0., yp0 = 0.;
233 float xp1 = 0., yp1 = 0.;
234 ToPlane(photon[0][0], photon[0][1], photon[0][2], xp0, yp0);
235 ToPlane(photon[1][0], photon[1][1], photon[1][2], xp1, yp1);
236 std::vector<float> xgr = {xp0, xp1};
237 std::vector<float> ygr = {yp0, yp1};
238 gr.DrawGraph(2, xgr.data(), ygr.data(), "Lsame");
239 }
240
241 if (!m_exc.empty()) {
242 DrawMarkers2d(m_exc, m_colExcitation, m_markerSizeCollision);
243 }
244 if (!m_ion.empty()) {
245 DrawMarkers2d(m_ion, m_colIonisation, m_markerSizeCollision);
246 }
247 if (!m_att.empty()) {
248 DrawMarkers2d(m_att, m_colAttachment, m_markerSizeCollision);
249 }
250
251 gPad->Update();
252}
253
254void ViewDrift::DrawMarkers2d(
255 const std::vector<std::array<float, 3> >& points, const short col,
256 const double size) {
257 if (points.empty()) return;
258 TGraph gr;
259 gr.SetMarkerColor(col);
260 gr.SetMarkerSize(size);
261 gr.SetMarkerStyle(20);
262 std::vector<float> xgr;
263 std::vector<float> ygr;
264 for (const auto& p : points) {
265 if (!InBox(p)) continue;
266 float xp = 0., yp = 0.;
267 ToPlane(p[0], p[1], p[2], xp, yp);
268 xgr.push_back(xp);
269 ygr.push_back(yp);
270 }
271 if (!xgr.empty()) {
272 gr.DrawGraph(xgr.size(), xgr.data(), ygr.data(), "Psame");
273 }
274}
275
276void ViewDrift::Plot3d(const bool axis, const bool ogl,
277 const bool snapshot) {
278 auto pad = GetCanvas();
279 pad->cd();
280 pad->SetTitle("Drift lines");
281 if (!pad->GetView()) {
282 if (!SetPlotLimits3d()) {
283 std::cerr << m_className << "::Plot3d:\n"
284 << " Could not determine the plot limits.\n";
285 }
286 auto view = TView::CreateView(1, 0, 0);
287 view->SetRange(m_xMinBox, m_yMinBox, m_zMinBox,
289 if (axis) view->ShowAxis();
290 pad->SetView(view);
291 if (ogl) pad->GetViewer3D("ogl");
292 }
293
294 if (snapshot) {
295 std::vector<std::array<float, 3> > electrons;
296 std::vector<std::array<float, 3> > holes;
297 std::vector<std::array<float, 3> > ions;
298 for (const auto& driftLine : m_driftLines) {
299 if (driftLine.second == Particle::Electron) {
300 electrons.push_back(driftLine.first.back());
301 } else if (driftLine.second == Particle::Hole) {
302 holes.push_back(driftLine.first.back());
303 } else {
304 ions.push_back(driftLine.first.back());
305 }
306 }
307 DrawMarkers3d(electrons, m_colElectron, m_markerSizeCollision);
308 DrawMarkers3d(holes, m_colHole, m_markerSizeCollision);
309 DrawMarkers3d(ions, m_colIon, m_markerSizeCollision);
310 } else {
311 for (const auto& driftLine : m_driftLines) {
312 std::vector<float> points;
313 for (const auto& p : driftLine.first) {
314 points.push_back(p[0]);
315 points.push_back(p[1]);
316 points.push_back(p[2]);
317 }
318 const int nP = driftLine.first.size();
319 TPolyLine3D pl(nP, points.data());
320 if (driftLine.second == Particle::Electron) {
321 pl.SetLineColor(m_colElectron);
322 } else if (driftLine.second == Particle::Hole) {
323 pl.SetLineColor(m_colHole);
324 } else {
325 pl.SetLineColor(m_colIon);
326 }
327 pl.SetLineWidth(1);
328 pl.DrawPolyLine(nP, points.data(), "same");
329 }
330 }
331 for (const auto& track : m_tracks) {
332 std::vector<float> points;
333 for (const auto& p : track) {
334 points.push_back(p[0]);
335 points.push_back(p[1]);
336 points.push_back(p[2]);
337 }
338 const int nP = track.size();
339 TPolyLine3D pl(nP, points.data());
340 pl.SetLineColor(m_colTrack);
341 pl.SetLineWidth(1);
342 pl.DrawPolyLine(nP, points.data(), "same");
343 if (m_drawClusters) {
344 DrawMarkers3d(track, m_colTrack, m_markerSizeCluster);
345 }
346 }
347
348 if (!m_exc.empty()) {
349 DrawMarkers3d(m_exc, m_colExcitation, m_markerSizeCollision);
350 }
351 if (!m_ion.empty()) {
352 DrawMarkers3d(m_ion, m_colIonisation, m_markerSizeCollision);
353 }
354 if (!m_att.empty()) {
355 DrawMarkers3d(m_att, m_colAttachment, m_markerSizeCollision);
356 }
357 pad->Modified();
358 pad->Update();
359
360 if (axis) {
361 TAxis3D* ax3d = TAxis3D::GetPadAxis();
362 if (ax3d) {
363 ax3d->SetLabelColor(kGray + 2);
364 ax3d->SetAxisColor(kGray + 2);
365 ax3d->SetXTitle("x");
366 ax3d->SetYTitle("y");
367 ax3d->SetZTitle("z");
368 }
369 pad->Update();
370 }
371}
372
373void ViewDrift::DrawMarkers3d(
374 const std::vector<std::array<float, 3> >& points, const short col,
375 const double size) {
376
377 const size_t nP = points.size();
378 std::vector<float> xyz;
379 for (size_t i = 0; i < nP; ++i) {
380 xyz.push_back(points[i][0]);
381 xyz.push_back(points[i][1]);
382 xyz.push_back(points[i][2]);
383 }
384 TPolyMarker3D pm(nP, xyz.data());
385 pm.SetMarkerColor(col);
386 pm.SetMarkerSize(size);
387 pm.DrawPolyMarker(nP, xyz.data(), 20, "same");
388}
389
390bool ViewDrift::SetPlotLimits2d() {
391
392 if (m_userPlotLimits) return true;
393 double xmin = 0., ymin = 0., xmax = 0., ymax = 0.;
394 if (m_userBox) {
395 if (PlotLimitsFromUserBox(xmin, ymin, xmax, ymax)) {
396 m_xMinPlot = xmin;
397 m_yMinPlot = ymin;
398 m_xMaxPlot = xmax;
399 m_yMaxPlot = ymax;
400 return true;
401 }
402 }
403
404 // Try to determine the limits from the drift lines themselves.
405 std::array<double, 3> bbmin;
406 std::array<double, 3> bbmax;
407 bbmin.fill(std::numeric_limits<double>::max());
408 bbmax.fill(-std::numeric_limits<double>::max());
409 for (const auto& driftLine : m_driftLines) {
410 for (const auto& p : driftLine.first) {
411 for (unsigned int i = 0; i < 3; ++i) {
412 bbmin[i] = std::min(bbmin[i], double(p[i]));
413 bbmax[i] = std::max(bbmax[i], double(p[i]));
414 }
415 }
416 }
417 for (const auto& track : m_tracks) {
418 for (const auto& p : track) {
419 for (unsigned int i = 0; i < 3; ++i) {
420 bbmin[i] = std::min(bbmin[i], double(p[i]));
421 bbmax[i] = std::max(bbmax[i], double(p[i]));
422 }
423 }
424 }
425 return PlotLimits(bbmin, bbmax,
427}
428
429bool ViewDrift::SetPlotLimits3d() {
430
431 if (m_userBox) return true;
432 if (m_driftLines.empty() && m_tracks.empty()) return false;
433 // Try to determine the limits from the drift lines themselves.
434 std::array<double, 3> bbmin;
435 std::array<double, 3> bbmax;
436 bbmin.fill(std::numeric_limits<double>::max());
437 bbmax.fill(-std::numeric_limits<double>::max());
438 for (const auto& driftLine : m_driftLines) {
439 for (const auto& p : driftLine.first) {
440 for (unsigned int i = 0; i < 3; ++i) {
441 bbmin[i] = std::min(bbmin[i], double(p[i]));
442 bbmax[i] = std::max(bbmax[i], double(p[i]));
443 }
444 }
445 }
446 for (const auto& track : m_tracks) {
447 for (const auto& p : track) {
448 for (unsigned int i = 0; i < 3; ++i) {
449 bbmin[i] = std::min(bbmin[i], double(p[i]));
450 bbmax[i] = std::max(bbmax[i], double(p[i]));
451 }
452 }
453 }
454 double r = 0.;
455 for (size_t i = 0; i < 3; ++i) r += fabs(bbmax[i] - bbmin[i]);
456 m_xMinBox = bbmin[0];
457 m_yMinBox = bbmin[1];
458 m_zMinBox = bbmin[2];
459 m_xMaxBox = bbmax[0];
460 m_yMaxBox = bbmax[1];
461 m_zMaxBox = bbmax[2];
462 if (fabs(m_xMaxBox - m_xMinBox) < 0.1 * r) {
463 m_xMinBox -= 0.1 * r;
464 m_xMaxBox += 0.1 * r;
465 }
466 if (fabs(m_yMaxBox - m_yMinBox) < 0.1 * r) {
467 m_yMinBox -= 0.1 * r;
468 m_yMaxBox += 0.1 * r;
469 }
470 if (fabs(m_zMaxBox - m_zMinBox) < 0.1 * r) {
471 m_zMinBox -= 0.1 * r;
472 m_zMaxBox += 0.1 * r;
473 }
474 return true;
475}
476
477}
std::string LabelY()
Definition ViewBase.cc:510
static void SetRange(TVirtualPad *pad, const double x0, const double y0, const double x1, const double y1)
Definition ViewBase.cc:93
std::string LabelX()
Definition ViewBase.cc:447
bool InBox(const std::array< T, 3 > &x) const
Definition ViewBase.hh:119
void DrawLine(const std::vector< std::array< float, 3 > > &xl, const short col, const short lw)
Definition ViewBase.cc:398
std::string m_className
Definition ViewBase.hh:82
TPad * GetCanvas()
Retrieve the canvas.
Definition ViewBase.cc:74
static bool RangeSet(TVirtualPad *)
Definition ViewBase.cc:83
bool PlotLimits(Sensor *sensor, double &xmin, double &ymin, double &xmax, double &ymax) const
Definition ViewBase.cc:635
void ToPlane(const T x, const T y, const T z, T &xp, T &yp) const
Definition ViewBase.hh:113
bool PlotLimitsFromUserBox(double &xmin, double &ymin, double &xmax, double &ymax) const
Definition ViewBase.cc:690
ViewBase()=delete
Default constructor.
void AddIonisation(const float x, const float y, const float z)
Definition ViewDrift.cc:150
void Plot2d(const bool axis=true, const bool snapshot=false)
Make a 2D plot of the drift lines in the current viewing plane.
Definition ViewDrift.cc:170
void AddDriftLinePoint(const size_t iL, const float x, const float y, const float z)
Definition ViewDrift.cc:112
void AddTrackPoint(const size_t iL, const float x, const float y, const float z)
Definition ViewDrift.cc:133
void NewChargedParticleTrack(const size_t np, size_t &id, const float x0, const float y0, const float z0)
Definition ViewDrift.cc:88
void SetTrackPoint(const size_t iL, const size_t iP, const float x, const float y, const float z)
Definition ViewDrift.cc:123
void Plot(const bool twod=false, const bool axis=true, const bool snapshot=false)
Draw the drift lines.
Definition ViewDrift.cc:162
void SetClusterMarkerSize(const double size)
Set the size of the cluster markers (see TAttMarker).
Definition ViewDrift.cc:38
void SetDriftLinePoint(const size_t iL, const size_t iP, const float x, const float y, const float z)
Definition ViewDrift.cc:101
void Plot3d(const bool axis=true, const bool ogl=true, const bool snapshot=false)
Make a 3D plot of the drift lines.
Definition ViewDrift.cc:276
void AddAttachment(const float x, const float y, const float z)
Definition ViewDrift.cc:156
ViewDrift()
Constructor.
Definition ViewDrift.cc:21
void GetDriftLine(const size_t i, std::vector< std::array< float, 3 > > &driftLine, bool &electron) const
Retrieve the coordinates of a given drift line.
Definition ViewDrift.cc:54
void Clear()
Delete existing drift lines, tracks and markers.
Definition ViewDrift.cc:29
void AddPhoton(const float x0, const float y0, const float z0, const float x1, const float y1, const float z1)
Definition ViewDrift.cc:80
size_t NewDriftLine(const Particle particle, const size_t np, const float x0, const float y0, const float z0)
Definition ViewDrift.cc:68
void AddExcitation(const float x, const float y, const float z)
Definition ViewDrift.cc:144
void SetCollisionMarkerSize(const double size)
Set the size of the collision markers (see TAttMarker).
Definition ViewDrift.cc:46
DoubleAc fabs(const DoubleAc &f)
Definition DoubleAc.h:615