Garfield++ 3.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
Garfield::ViewIsochrons Class Reference

Draw equal time contour lines. More...

#include <ViewIsochrons.hh>

+ Inheritance diagram for Garfield::ViewIsochrons:

Public Member Functions

 ViewIsochrons ()
 Constructor.
 
 ~ViewIsochrons ()=default
 Destructor.
 
void SetSensor (Sensor *s)
 Set the sensor.
 
void SetComponent (ComponentBase *c)
 Set the component.
 
void SetArea (const double xmin, const double ymin, const double xmax, const double ymax)
 Set the viewing area (in local coordinates of the current viewing plane).
 
void SetArea ()
 Set the viewing area based on the bounding box of the sensor/component.
 
void SetPlane (const double fx, const double fy, const double fz, const double x0, const double y0, const double z0)
 
void SetDefaultProjection ()
 Set the default viewing plane ( $x$- $y$ at $z = 0$).
 
void Rotate (const double angle)
 Rotate the viewing plane (angle in radian).
 
void PlotIsochrons (const double tstep, const std::vector< std::array< double, 3 > > &points, const bool rev=false, const bool colour=false, const bool markers=false, const bool plotDriftLines=true)
 
void DriftElectrons (const bool positive=false)
 
void DriftIons (const bool negative=false)
 Request ion drift lines with positive (default) or negative charge.
 
void EnableSorting (const bool on=true)
 Sort (or not) the points on a contour line (default: sorting is done).
 
void CheckCrossings (const bool on=true)
 
void SetAspectRatioSwitch (const double ar)
 
void SetLoopThreshold (const double thr)
 
void SetConnectionThreshold (const double thr)
 
- Public Member Functions inherited from Garfield::ViewBase
 ViewBase ()=delete
 Default constructor.
 
 ViewBase (const std::string &name)
 Constructor.
 
virtual ~ViewBase ()
 Destructor.
 
void SetCanvas (TCanvas *c)
 Set the canvas to be painted on.
 
TCanvas * GetCanvas ()
 Retrieve the canvas.
 
void EnableDebugging (const bool on=true)
 Switch on/off debugging output.
 

Additional Inherited Members

- Protected Member Functions inherited from Garfield::ViewBase
std::string FindUnusedFunctionName (const std::string &s) const
 
std::string FindUnusedHistogramName (const std::string &s) const
 
- Protected Attributes inherited from Garfield::ViewBase
std::string m_className = "ViewBase"
 
bool m_debug = false
 
TCanvas * m_canvas = nullptr
 
bool m_hasExternalCanvas = false
 
double m_proj [3][3]
 

Detailed Description

Draw equal time contour lines.

Definition at line 13 of file ViewIsochrons.hh.

Constructor & Destructor Documentation

◆ ViewIsochrons()

Garfield::ViewIsochrons::ViewIsochrons ( )

Constructor.

Definition at line 135 of file ViewIsochrons.cc.

135 : ViewBase("ViewIsochrons") {
137}
ViewBase()=delete
Default constructor.
void SetDefaultProjection()
Set the default viewing plane ( - at ).

◆ ~ViewIsochrons()

Garfield::ViewIsochrons::~ViewIsochrons ( )
default

Destructor.

Member Function Documentation

◆ CheckCrossings()

void Garfield::ViewIsochrons::CheckCrossings ( const bool  on = true)
inline

Check (or not) that drift-lines do not cross isochrons (default: check is done).

Definition at line 72 of file ViewIsochrons.hh.

72{ m_checkCrossings = on; }

◆ DriftElectrons()

void Garfield::ViewIsochrons::DriftElectrons ( const bool  positive = false)
inline

Request electron drift lines with negative (default) or positive charge.

Definition at line 59 of file ViewIsochrons.hh.

59 {
60 m_particle = Particle::Electron;
61 m_positive = positive;
62 }

◆ DriftIons()

void Garfield::ViewIsochrons::DriftIons ( const bool  negative = false)
inline

Request ion drift lines with positive (default) or negative charge.

Definition at line 64 of file ViewIsochrons.hh.

64 {
65 m_particle = Particle::Ion;
66 m_positive = !negative;
67 }

◆ EnableSorting()

void Garfield::ViewIsochrons::EnableSorting ( const bool  on = true)
inline

Sort (or not) the points on a contour line (default: sorting is done).

Definition at line 69 of file ViewIsochrons.hh.

69{ m_sortContours = on; }

◆ PlotIsochrons()

void Garfield::ViewIsochrons::PlotIsochrons ( const double  tstep,
const std::vector< std::array< double, 3 > > &  points,
const bool  rev = false,
const bool  colour = false,
const bool  markers = false,
const bool  plotDriftLines = true 
)

Draw equal time contour lines.

Parameters
tstepTime interval.
pointsList of starting points.
revIf true, the drift time is measured from the end points of the drift lines.
colourDraw contour lines using colours.
markersDraw markers (as opposed to lines).
plotDriftLinesDraw drift lines together with the isochrons.

Definition at line 204 of file ViewIsochrons.cc.

206 {
207
208 if (!m_sensor && !m_component) {
209 std::cerr << m_className << "::PlotIsochrons:\n"
210 << " Neither sensor nor component are defined.\n";
211 return;
212 }
213 if (tstep <= 0.) {
214 std::cerr << m_className << "::PlotIsochrons: Time step must be > 0.\n";
215 return;
216 }
217 if (points.empty()) {
218 std::cerr << m_className << "::PlotIsochrons:\n"
219 << " No starting points provided.\n";
220 return;
221 }
222 SetupCanvas();
223 if (!Range()) return;
224 auto frame = m_canvas->DrawFrame(m_xmin, m_ymin, m_xmax, m_ymax);
225 frame->GetXaxis()->SetTitle(m_xLabel);
226 frame->GetYaxis()->SetTitle(m_yLabel);
227 m_canvas->Update();
228
229 //-----------------------------------------------------------------------
230 // DRFEQT - The main routine (DRFEQT) accumulates equal drift time data
231 // DRFEQP which is plotted as a set of contours in the entry DRFEQP.
232 //-----------------------------------------------------------------------
233 std::vector<std::vector<std::array<double, 3> > > driftLines;
234 std::vector<std::array<double, 3> > startPoints;
235 std::vector<std::array<double, 3> > endPoints;
236 std::vector<int> statusCodes;
237 // Accumulate drift lines.
238 ComputeDriftLines(tstep, points, driftLines, startPoints, endPoints,
239 statusCodes, rev);
240 const unsigned int nDriftLines = driftLines.size();
241 if (nDriftLines < 2) {
242 std::cerr << m_className << "::PlotIsochrons: Too few drift lines.\n";
243 return;
244 }
245 // Keep track of the largest number of contours.
246 std::size_t nContours = 0;
247 for (const auto& driftLine : driftLines) {
248 nContours = std::max(nContours, driftLine.size());
249 }
250 if (nContours == 0) {
251 std::cerr << m_className << "::PlotIsochrons: No contour lines.\n";
252 return;
253 }
254
255 std::set<int> allStats;
256 for (const auto stat : statusCodes) allStats.insert(stat);
257
258 // DRFEQP
259 if (m_debug) {
260 std::cout << m_className << "::PlotIsochrons:\n"
261 << " Drawing " << nContours << " contours, "
262 << nDriftLines << " drift lines.\n";
263 std::printf(" Connection threshold: %10.3f\n", m_connectionThreshold);
264 std::printf(" Aspect ratio threshold: %10.3f\n", m_aspectRatio);
265 std::printf(" Loop closing threshold: %10.3f\n", m_loopThreshold);
266 if (m_sortContours) {
267 std::cout << " Sort contours.\n";
268 } else {
269 std::cout << " Do not sort contours.\n";
270 }
271 if (m_checkCrossings) {
272 std::cout << " Check for crossings.\n";
273 } else {
274 std::cout << " Do not check for crossings.\n";
275 }
276 if (markers) {
277 std::cout << " Mark isochron points.\n";
278 } else {
279 std::cout << " Draw isochron lines.\n";
280 }
281 }
282
283 // Loop over the equal time contours.
284 TGraph graph;
285 graph.SetLineColor(kGray + 2);
286 graph.SetMarkerColor(kGray + 2);
287 graph.SetLineStyle(m_lineStyle);
288 graph.SetMarkerStyle(m_markerStyle);
289 const double colRange = double(gStyle->GetNumberOfColors()) / nContours;
290 for (unsigned int ic = 0; ic < nContours; ++ic) {
291 if (colour) {
292 const auto col = gStyle->GetColorPalette(int((ic + 0.99) * colRange));
293 graph.SetLineColor(col);
294 graph.SetMarkerColor(col);
295 }
296 for (int stat : allStats) {
297 std::vector<std::pair<std::array<double, 4>, unsigned int> > contour;
298 // Loop over the drift lines, picking up the points when OK.
299 for (unsigned int k = 0; k < nDriftLines; ++k) {
300 const auto& dl = driftLines[k];
301 // Reject any undesirable combinations.
302 if (statusCodes[k] != stat || ic >= dl.size()) continue;
303 // Add the point to the contour line.
304 std::array<double, 4> point = {dl[ic][0], dl[ic][1], dl[ic][2], 0.};
305 contour.push_back(std::make_pair(point, k));
306 }
307 // Skip the plot of this contour if there are no points.
308 if (contour.empty()) continue;
309 bool circle = false;
310 // If requested, sort the points on the contour line.
311 if (m_sortContours && !markers) SortContour(contour, circle);
312 // Plot this contour.
313 if (markers) {
314 // Simply mark the contours if this was requested.
315 std::vector<double> xp;
316 std::vector<double> yp;
317 std::vector<double> zp;
318 for (const auto& point : contour) {
319 const double x = point.first[0];
320 const double y = point.first[1];
321 const double z = point.first[2];
322 xp.push_back(m_proj[0][0] * x + m_proj[1][0] * y + z * m_plane[0]);
323 yp.push_back(m_proj[0][1] * x + m_proj[1][1] * y + z * m_plane[1]);
324 zp.push_back(m_proj[0][2] * x + m_proj[1][2] * y + z * m_plane[2]);
325 }
326 graph.DrawGraph(xp.size(), xp.data(), yp.data(), "Psame");
327 continue;
328 }
329 // Regular plotting.
330 const double tolx = (m_xmax - m_xmin) * m_connectionThreshold;
331 const double toly = (m_ymax - m_ymin) * m_connectionThreshold;
332 // Flag to keep track if the segment is interrupted by a drift line
333 // or if it is too long.
334 bool gap = false;
335 // Coordinates to be plotted.
336 std::vector<double> xp;
337 std::vector<double> yp;
338 std::vector<double> zp;
339 const unsigned int nP = contour.size();
340 for (unsigned int i = 0; i < nP; ++i) {
341 gap = false;
342 const auto x0 = contour[i].first[0];
343 const auto y0 = contour[i].first[1];
344 const auto z0 = contour[i].first[2];
345 xp.push_back(m_proj[0][0] * x0 + m_proj[1][0] * y0 + z0 * m_plane[0]);
346 yp.push_back(m_proj[0][1] * x0 + m_proj[1][1] * y0 + z0 * m_plane[1]);
347 zp.push_back(m_proj[0][2] * x0 + m_proj[1][2] * y0 + z0 * m_plane[2]);
348 if (i == nP - 1) break;
349 const auto x1 = contour[i + 1].first[0];
350 const auto y1 = contour[i + 1].first[1];
351 // Reject contour segments which are long compared with AREA.
352 if (fabs(x1 - x0) > tolx || fabs(y1 - y0) > toly) gap = true;
353 // Get the indices of the drift lines corresponding
354 // to these two points on the contour line.
355 const auto i0 = contour[i].second;
356 const auto i1 = contour[i + 1].second;
357 // Set the BREAK flag if it crosses some stored drift line segment.
358 if (m_checkCrossings && !gap) {
359 for (unsigned int k = 0; k < nDriftLines; ++k) {
360 const auto& dl = driftLines[k];
361 for (unsigned int jc = 0; jc < dl.size(); ++jc) {
362 if ((i0 == k || i1 == k) && (jc == ic || jc + 1 == ic)) {
363 continue;
364 }
365 const auto& p0 = dl[jc];
366 const auto& p1 = jc == dl.size() - 1 ? endPoints[k] : dl[jc + 1];
367 if (Crossing(p0[0], p0[1], p1[0], p1[1], x0, y0, x1, y1)) {
368 gap = true;
369 break;
370 }
371 }
372 if (gap) break;
373 if ((i0 == k || i1 == k) && ic == 0) continue;
374 const auto& p0 = startPoints[k];
375 if (Crossing(p0[0], p0[1], dl[0][0], dl[0][1],
376 x0, y0, x1, y1)) {
377 gap = true;
378 break;
379 }
380 }
381 }
382 // If there has been a break, plot what we have already.
383 if (gap) {
384 if (xp.size() > 1) {
385 // Plot line.
386 graph.DrawGraph(xp.size(), xp.data(), yp.data(), "Lsame");
387 } else {
388 // Plot markers.
389 graph.DrawGraph(xp.size(), xp.data(), yp.data(), "Psame");
390 }
391 xp.clear();
392 yp.clear();
393 zp.clear();
394 }
395 }
396 // Plot the remainder.
397 if (xp.size() > 1) {
398 graph.DrawGraph(xp.size(), xp.data(), yp.data(), "Lsame");
399 } else if (!xp.empty()) {
400 graph.DrawGraph(xp.size(), xp.data(), yp.data(), "Psame");
401 }
402 }
403 }
404
405 gPad->Update();
406 if (!plotDriftLines) return;
407
408 graph.SetLineStyle(1);
409 if (m_particle == Particle::Electron) {
410 graph.SetLineColor(kOrange - 3);
411 } else {
412 graph.SetLineColor(kRed + 1);
413 }
414 for (unsigned int i = 0; i < nDriftLines; ++i) {
415 std::vector<double> xp;
416 std::vector<double> yp;
417 const double x0 = startPoints[i][0];
418 const double y0 = startPoints[i][1];
419 const double z0 = startPoints[i][2];
420 xp.push_back(m_proj[0][0] * x0 + m_proj[1][0] * y0 + z0 * m_plane[0]);
421 yp.push_back(m_proj[0][1] * x0 + m_proj[1][1] * y0 + z0 * m_plane[1]);
422 for (const auto& point : driftLines[i]) {
423 const double x = point[0];
424 const double y = point[1];
425 const double z = point[2];
426 xp.push_back(m_proj[0][0] * x + m_proj[1][0] * y + z * m_plane[0]);
427 yp.push_back(m_proj[0][1] * x + m_proj[1][1] * y + z * m_plane[1]);
428 }
429 const double x1 = endPoints[i][0];
430 const double y1 = endPoints[i][1];
431 const double z1 = endPoints[i][2];
432 xp.push_back(m_proj[0][0] * x1 + m_proj[1][0] * y1 + z1 * m_plane[0]);
433 yp.push_back(m_proj[0][1] * x1 + m_proj[1][1] * y1 + z1 * m_plane[1]);
434 graph.DrawGraph(xp.size(), xp.data(), yp.data(), "Lsame");
435 }
436}
std::string m_className
Definition: ViewBase.hh:28
TCanvas * m_canvas
Definition: ViewBase.hh:34
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:615

◆ Rotate()

void Garfield::ViewIsochrons::Rotate ( const double  angle)

Rotate the viewing plane (angle in radian).

Definition at line 814 of file ViewIsochrons.cc.

814 {
815 // Rotate the axes
816 double auxu[3], auxv[3];
817 const double ctheta = cos(theta);
818 const double stheta = sin(theta);
819 for (int i = 0; i < 3; ++i) {
820 auxu[i] = ctheta * m_proj[0][i] - stheta * m_proj[1][i];
821 auxv[i] = stheta * m_proj[0][i] + ctheta * m_proj[1][i];
822 }
823 for (int i = 0; i < 3; ++i) {
824 m_proj[0][i] = auxu[i];
825 m_proj[1][i] = auxv[i];
826 }
827
828 // Make labels to be placed along the axes
829 Labels();
830}
DoubleAc cos(const DoubleAc &f)
Definition: DoubleAc.cpp:432
DoubleAc sin(const DoubleAc &f)
Definition: DoubleAc.cpp:384

◆ SetArea() [1/2]

void Garfield::ViewIsochrons::SetArea ( )
inline

Set the viewing area based on the bounding box of the sensor/component.

Definition at line 29 of file ViewIsochrons.hh.

29{ m_hasUserArea = false; }

◆ SetArea() [2/2]

void Garfield::ViewIsochrons::SetArea ( const double  xmin,
const double  ymin,
const double  xmax,
const double  ymax 
)

Set the viewing area (in local coordinates of the current viewing plane).

Definition at line 159 of file ViewIsochrons.cc.

160 {
161 // Check range, assign if non-null.
162 if (xmin == xmax || ymin == ymax) {
163 std::cerr << m_className << "::SetArea: Null area range is not permitted.\n"
164 << " " << xmin << " < x < " << xmax << "\n"
165 << " " << ymin << " < y < " << ymax << "\n";
166 return;
167 }
168 m_xmin = std::min(xmin, xmax);
169 m_ymin = std::min(ymin, ymax);
170 m_xmax = std::max(xmin, xmax);
171 m_ymax = std::max(ymin, ymax);
172 m_hasUserArea = true;
173}

◆ SetAspectRatioSwitch()

void Garfield::ViewIsochrons::SetAspectRatioSwitch ( const double  ar)

Set the aspect ratio above which an isochron is considered linear (as opposed to circular).

Definition at line 175 of file ViewIsochrons.cc.

175 {
176
177 if (ar < 0.) {
178 std::cerr << m_className << "::SetAspectRatioSwitch: Value must be > 0.\n";
179 return;
180 }
181 m_aspectRatio = ar;
182}

◆ SetComponent()

void Garfield::ViewIsochrons::SetComponent ( ComponentBase c)

Set the component.

Definition at line 149 of file ViewIsochrons.cc.

149 {
150 if (!c) {
151 std::cerr << m_className << "::SetComponent: Null pointer.\n";
152 return;
153 }
154
155 m_component = c;
156 m_sensor = nullptr;
157}

◆ SetConnectionThreshold()

void Garfield::ViewIsochrons::SetConnectionThreshold ( const double  thr)

Fractional distance over which isochron segments are connected (default: 0.2).

Definition at line 194 of file ViewIsochrons.cc.

194 {
195
196 if (thr < 0. || thr > 1.) {
197 std::cerr << m_className << "::SetConnectionThreshold:\n"
198 << " Value must be between 0 and 1.\n";
199 return;
200 }
201 m_connectionThreshold = thr;
202}

◆ SetDefaultProjection()

void Garfield::ViewIsochrons::SetDefaultProjection ( )

Set the default viewing plane ( $x$- $y$ at $z = 0$).

Definition at line 520 of file ViewIsochrons.cc.

520 {
521 // Default projection: x-y at z=0
522 m_proj[0][0] = 1;
523 m_proj[1][0] = 0;
524 m_proj[2][0] = 0;
525 m_proj[0][1] = 0;
526 m_proj[1][1] = 1;
527 m_proj[2][1] = 0;
528 m_proj[0][2] = 0;
529 m_proj[1][2] = 0;
530 m_proj[2][2] = 0;
531
532 // Plane description
533 m_plane[0] = 0;
534 m_plane[1] = 0;
535 m_plane[2] = 1;
536 m_plane[3] = 0;
537
538 // Prepare axis labels.
539 Labels();
540}

Referenced by ViewIsochrons().

◆ SetLoopThreshold()

void Garfield::ViewIsochrons::SetLoopThreshold ( const double  thr)

Fractional distance between two points for closing a circular isochron (default: 0.2).

Definition at line 184 of file ViewIsochrons.cc.

184 {
185
186 if (thr < 0. || thr > 1.) {
187 std::cerr << m_className << "::SetLoopThreshold:\n"
188 << " Value must be between 0 and 1.\n";
189 return;
190 }
191 m_loopThreshold = thr;
192}

◆ SetPlane()

void Garfield::ViewIsochrons::SetPlane ( const double  fx,
const double  fy,
const double  fz,
const double  x0,
const double  y0,
const double  z0 
)

Set the projection (viewing plane).

Parameters
fx,fy,fznormal vector
x0,y0,z0in-plane point

Definition at line 773 of file ViewIsochrons.cc.

774 {
775 // Calculate two in-plane vectors for the normal vector
776 const double fnorm = sqrt(fx * fx + fy * fy + fz * fz);
777 if (fnorm > 0 && fx * fx + fz * fz > 0) {
778 const double fxz = sqrt(fx * fx + fz * fz);
779 m_proj[0][0] = fz / fxz;
780 m_proj[0][1] = 0;
781 m_proj[0][2] = -fx / fxz;
782 m_proj[1][0] = -fx * fy / (fxz * fnorm);
783 m_proj[1][1] = (fx * fx + fz * fz) / (fxz * fnorm);
784 m_proj[1][2] = -fy * fz / (fxz * fnorm);
785 m_proj[2][0] = x0;
786 m_proj[2][1] = y0;
787 m_proj[2][2] = z0;
788 } else if (fnorm > 0 && fy * fy + fz * fz > 0) {
789 const double fyz = sqrt(fy * fy + fz * fz);
790 m_proj[0][0] = (fy * fy + fz * fz) / (fyz * fnorm);
791 m_proj[0][1] = -fx * fz / (fyz * fnorm);
792 m_proj[0][2] = -fy * fz / (fyz * fnorm);
793 m_proj[1][0] = 0;
794 m_proj[1][1] = fz / fyz;
795 m_proj[1][2] = -fy / fyz;
796 m_proj[2][0] = x0;
797 m_proj[2][1] = y0;
798 m_proj[2][2] = z0;
799 } else {
800 std::cout << m_className << "::SetPlane:\n"
801 << " Normal vector has zero norm. No new projection set.\n";
802 }
803
804 // Store the plane description
805 m_plane[0] = fx;
806 m_plane[1] = fy;
807 m_plane[2] = fz;
808 m_plane[3] = fx * x0 + fy * y0 + fz * z0;
809
810 // Make labels to be placed along the axes
811 Labels();
812}
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314

◆ SetSensor()

void Garfield::ViewIsochrons::SetSensor ( Sensor s)

Set the sensor.

Definition at line 139 of file ViewIsochrons.cc.

139 {
140 if (!s) {
141 std::cerr << m_className << "::SetSensor: Null pointer.\n";
142 return;
143 }
144
145 m_sensor = s;
146 m_component = nullptr;
147}

The documentation for this class was generated from the following files: