Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ViewCell.cc
Go to the documentation of this file.
1#include <iostream>
2#include <cmath>
3
4#include <TMarker.h>
5#include <TEllipse.h>
6#include <TLine.h>
7#include <TPolyLine.h>
8#include <TGeoPgon.h>
9
11#include "Plotting.hh"
12#include "ViewCell.hh"
13
14namespace Garfield {
15
17 : m_className("ViewCell"),
18 m_debug(false),
19 m_useWireMarker(true),
20 m_label("Cell Layout"),
21 m_canvas(NULL),
22 m_hasExternalCanvas(false),
23 m_hasUserArea(false),
24 m_xMin(-1.),
25 m_yMin(-1.),
26 m_zMin(-1.),
27 m_xMax(1.),
28 m_yMax(1.),
29 m_zMax(1.),
30 m_component(NULL),
31 m_geoManager(NULL) {
32
34}
35
37
38 if (!m_hasExternalCanvas && m_canvas != NULL) delete m_canvas;
39 Reset();
40
41}
42
44
45 if (comp == NULL) {
46 std::cerr << m_className << "::SetComponent:\n";
47 std::cerr << " Component pointer is null.\n";
48 return;
49 }
50
51 m_component = comp;
52}
53
54void ViewCell::SetCanvas(TCanvas* c) {
55
56 if (c == NULL) return;
57 if (!m_hasExternalCanvas && m_canvas != NULL) {
58 delete m_canvas;
59 m_canvas = NULL;
60 }
61 m_canvas = c;
62 m_hasExternalCanvas = true;
63}
64
65void ViewCell::SetArea(const double& xmin, const double& ymin,
66 const double& zmin,
67 const double& xmax, const double& ymax,
68 const double& zmax) {
69
70 // Check range, assign if non-null
71 if (xmin == xmax || ymin == ymax || zmin == zmax) {
72 std::cout << m_className << "::SetArea:\n";
73 std::cout << " Null area range not permitted.\n";
74 return;
75 }
76 m_xMin = std::min(xmin, xmax);
77 m_yMin = std::min(ymin, ymax);
78 m_zMin = std::min(zmin, zmax);
79 m_xMax = std::max(xmin, xmax);
80 m_yMax = std::max(ymin, ymax);
81 m_zMax = std::max(zmin, zmax);
82 m_hasUserArea = true;
83}
84
85void ViewCell::SetArea() { m_hasUserArea = false; }
86
88
89 if (!Plot(false)) {
90 std::cerr << m_className << "::Plot2d:\n";
91 std::cerr << " Error creating 2d plot.\n";
92 }
93}
94
96
97 if (!Plot(true)) {
98 std::cerr << m_className << "::Plot3d:\n";
99 std::cerr << " Error creating 3d plot.\n";
100 }
101}
102
103bool ViewCell::Plot(const bool use3d) {
104
105 if (m_component == NULL) {
106 std::cerr << m_className << "::Plot:\n";
107 std::cerr << " Component is not defined.\n";
108 return false;
109 }
110
111 double pmin = 0., pmax = 0.;
112 if (!m_component->GetVoltageRange(pmin, pmax)) {
113 std::cerr << m_className << "::Plot:\n";
114 std::cerr << " Component is not ready.\n";
115 return false;
116 }
117
118 // Get the bounding box
119 double x0 = m_xMin, y0 = m_yMin, z0 = m_zMin;
120 double x1 = m_xMax, y1 = m_yMax, z1 = m_zMax;
121 if (!m_hasUserArea) {
122 if (!m_component->GetBoundingBox(x0, y0, z0, x1, y1, z1)) {
123 std::cerr << m_className << "::Plot:\n";
124 std::cerr << " Bounding box cannot be determined.\n";
125 std::cerr << " Call SetArea first.\n";
126 return false;
127 }
128 }
129 // Get the max. half-length in z.
130 const double dx = std::max(fabs(x0), fabs(x1));
131 const double dy = std::max(fabs(y0), fabs(y1));
132 const double dz = std::max(fabs(z0), fabs(z1));
133
134 if (m_canvas == NULL) {
135 m_canvas = new TCanvas();
136 if (!use3d) m_canvas->SetTitle(m_label.c_str());
137 if (m_hasExternalCanvas) m_hasExternalCanvas = false;
138 }
139 if (!use3d) {
140 m_canvas->Range(x0 - 0.1 * (x1 - x0), y0 - 0.1 * (y1 - y0),
141 x1 + 0.1 * (x1 - x0), y1 + 0.1 * (y1 - y0));
142 }
143 m_canvas->cd();
144
145 // Get the cell type.
146 const std::string cellType = m_component->GetCellType();
147
148 // Get the periodicities.
149 double sx = 0., sy = 0.;
150 const bool perX = m_component->GetPeriodicityX(sx);
151 const bool perY = m_component->GetPeriodicityY(sy);
152 // Determine the number of periods present in the cell.
153 int nMaxX = 0, nMinX = 0;
154 int nMaxY = 0, nMinY = 0;
155 if (perX) {
156 nMinX = int(x0 / sx) - 1;
157 nMaxX = int(x1 / sx) + 1;
158 }
159 if (perY) {
160 nMinY = int(y0 / sy) - 1;
161 nMaxY = int(y1 / sy) + 1;
162 }
163
164 if (use3d) {
165 Reset();
166 m_geoManager = new TGeoManager("ViewCellGeoManager", m_label.c_str());
167 TGeoMaterial* matVacuum = new TGeoMaterial("Vacuum", 0., 0., 0.);
168 TGeoMaterial* matMetal = new TGeoMaterial("Metal", 63.546, 29., 8.92);
169 TGeoMedium* medVacuum = new TGeoMedium("Vacuum", 1, matVacuum);
170 TGeoMedium* medMetal = new TGeoMedium("Metal", 1, matMetal);
171 m_media.push_back(medVacuum);
172 m_media.push_back(medMetal);
173 TGeoVolume* world = m_geoManager->MakeBox("World", medVacuum,
174 1.05 * dx, 1.05 * dy, 1.05 * dz);
175 m_geoManager->SetTopVolume(world);
176 m_volumes.push_back(world);
177 }
178 // Get the number of wires.
179 const int nWires = m_component->GetNumberOfWires();
180 int nWireTypes = 0;
181 std::vector<std::string> wireTypes;
182 wireTypes.clear();
183 // Loop over the wires.
184 for (int i = nWires; i--;) {
185 double xw = 0., yw = 0., dw = 0., vw = 0., lw = 0., qw = 0.;
186 std::string lbl;
187 int type = -1;
188 int nTrap;
189 m_component->GetWire(i, xw, yw, dw, vw, lbl, lw, qw, nTrap);
190 // Check if other wires with the same label already exist.
191 if (nWireTypes == 0) {
192 wireTypes.push_back(lbl);
193 type = 0;
194 ++nWireTypes;
195 } else {
196 for (int j = nWireTypes; j--;) {
197 if (lbl == wireTypes[j]) {
198 type = j;
199 break;
200 }
201 }
202 if (type < 0) {
203 wireTypes.push_back(lbl);
204 type = nWireTypes;
205 ++nWireTypes;
206 }
207 }
208 for (int nx = nMinX; nx <= nMaxX; ++nx) {
209 for (int ny = nMinY; ny <= nMaxY; ++ny) {
210 const double x = xw + nx * sx;
211 const double y = yw + ny * sy;
212 if (x + 0.5 * dw <= x0 || x - 0.5 * dw >= x1 || y + 0.5 * dw <= y0 ||
213 y - 0.5 * dw >= y1) {
214 continue;
215 }
216 if (use3d) {
217 TGeoVolume* wire = m_geoManager->MakeTube("Wire", m_media[1],
218 0., 0.5 * dw,
219 std::min(0.5 * lw, dz));
220 switch (type) {
221 case 0:
222 wire->SetLineColor(kBlue);
223 break;
224 case 1:
225 wire->SetLineColor(kRed + 2);
226 break;
227 case 2:
228 wire->SetLineColor(kPink + 3);
229 break;
230 case 3:
231 wire->SetLineColor(kCyan + 3);
232 break;
233 default:
234 wire->SetLineColor(kBlue + type);
235 break;
236 }
237 m_volumes.push_back(wire);
238 m_geoManager->GetTopVolume()->AddNode(wire, 1,
239 new TGeoTranslation(x, y, 0.));
240 } else {
241 PlotWire(x, y, dw, type);
242 }
243 }
244 }
245 }
246
247 // Draw lines at the positions of the x planes.
248 const int nPlanesX = m_component->GetNumberOfPlanesX();
249 for (int i = nPlanesX; i--;) {
250 double xp = 0., vp = 0.;
251 std::string lbl;
252 m_component->GetPlaneX(i, xp, vp, lbl);
253 for (int nx = nMinX; nx <= nMaxX; ++nx) {
254 const double x = xp + nx * sx;
255 if (x < x0 || x > x1) continue;
256 if (use3d) {
257 const double width = 0.01;
258 TGeoVolume* plane = m_geoManager->MakeBox("PlaneX", m_media[1],
259 width, dy, dz);
260 plane->SetLineColor(kGreen + 2);
261 m_volumes.push_back(plane);
262 m_geoManager->GetTopVolume()->AddNode(plane, 1,
263 new TGeoTranslation(x, 0., 0.));
264 } else {
265 PlotLine(x, y0, x, y1);
266 }
267 }
268 }
269
270 // Draw lines at the positions of the y planes.
271 const int nPlanesY = m_component->GetNumberOfPlanesY();
272 for (int i = nPlanesY; i--;) {
273 double yp = 0., vp = 0.;
274 std::string lbl;
275 m_component->GetPlaneY(i, yp, vp, lbl);
276 for (int ny = nMinY; ny <= nMaxY; ++ny) {
277 const double y = yp + ny * sy;
278 if (y < y0 || y > y1) continue;
279 if (use3d) {
280 const double width = 0.01;
281 TGeoVolume* plane = m_geoManager->MakeBox("PlaneY", m_media[1],
282 dx, width, dz);
283 plane->SetLineColor(kGreen + 2);
284 m_volumes.push_back(plane);
285 m_geoManager->GetTopVolume()->AddNode(plane, 1,
286 new TGeoTranslation(0., y, 0.));
287 } else {
288 PlotLine(x0, y, x1, y);
289 }
290 }
291 }
292
293 double rt = 0., vt = 0.;
294 int nt = 0;
295 std::string lbl;
296 if (m_component->GetTube(rt, vt, nt, lbl)) {
297 if (use3d) {
298 if (nt <= 0) {
299 // Round tube
300 TGeoVolume* tube = m_geoManager->MakeTube("Tube", m_media[1],
301 0.98 * rt, 1.02 * rt, dz);
302 tube->SetLineColor(kGreen + 2);
303 m_volumes.push_back(tube);
304 m_geoManager->GetTopVolume()->AddNode(tube, 1,
305 new TGeoTranslation(0., 0., 0.));
306 } else {
307 TGeoVolume* tube = m_geoManager->MakePgon("Tube", m_media[1],
308 0., 360., nt, 2);
309 TGeoPgon* pgon = dynamic_cast<TGeoPgon*>(tube->GetShape());
310 pgon->DefineSection(0, -dz, 0.98 * rt, 1.02 * rt);
311 pgon->DefineSection(1, +dz, 0.98 * rt, 1.02 * rt);
312 tube->SetLineColor(kGreen + 2);
313 m_volumes.push_back(tube);
314 m_geoManager->GetTopVolume()->AddNode(tube, 1,
315 new TGeoTranslation(0., 0., 0.));
316 }
317 } else {
318 PlotTube(0., 0., rt, nt);
319 }
320 }
321
322 if (use3d) {
323 m_geoManager->CloseGeometry();
324 m_geoManager->GetTopNode()->Draw("ogl");
325 } else {
326 m_canvas->Update();
327 }
328
329 return true;
330}
331
332void ViewCell::PlotWire(const double& x, const double& y, const double& d,
333 const int& type) {
334
335 if (m_useWireMarker) {
336 int markerStyle = 1;
337 if (type == 0) {
338 markerStyle = kFullCircle;
339 } else if (type == 1) {
340 markerStyle = kOpenCircle;
341 } else if (type == 2) {
342 markerStyle = kFullSquare;
343 } else if (type == 3) {
344 markerStyle = kOpenSquare;
345 } else {
346 markerStyle = 26 + type;
347 }
348 TMarker* marker = new TMarker(x, y, markerStyle);
349 marker->Draw("P");
350 return;
351 }
352
353 TEllipse* circle = new TEllipse(x, y, 0.5 * d);
354 circle->Draw("");
355}
356
357void ViewCell::PlotLine(const double& x0, const double& y0,
358 const double& x1, const double& y1) {
359
360 TLine* line = new TLine(x0, y0, x1, y1);
361 line->Draw("");
362}
363
364void ViewCell::PlotTube(const double& x0, const double& y0, const double& r,
365 const int& n) {
366
367 if (n <= 0) {
368 TEllipse* circle = new TEllipse(x0, y0, r);
369 circle->SetFillStyle(0);
370 circle->Draw("");
371 return;
372 }
373
374 TPolyLine* pline = new TPolyLine(n + 1);
375 for (int i = 0; i <= n; ++i) {
376 const double x = x0 + r * cos(i * TwoPi / double(n));
377 const double y = y0 + r * sin(i * TwoPi / double(n));
378 pline->SetPoint(i, x, y);
379 }
380 pline->Draw("");
381}
382
383void ViewCell::Reset() {
384
385 for (std::vector<TGeoVolume*>::iterator it = m_volumes.begin();
386 it != m_volumes.end(); ++it) {
387 if (*it) {
388 TGeoShape* shape = (*it)->GetShape();
389 if (shape) delete shape;
390 delete *it;
391 }
392 }
393 m_volumes.clear();
394 for (std::vector<TGeoMedium*>::iterator it = m_media.begin();
395 it != m_media.end(); ++it) {
396 if (*it) {
397 TGeoMaterial* material = (*it)->GetMaterial();
398 if (material) delete material;
399 delete *it;
400 }
401 }
402 m_media.clear();
403
404 if (m_geoManager) {
405 delete m_geoManager;
406 m_geoManager = NULL;
407 }
408
409}
410
411}
DoubleAc cos(const DoubleAc &f)
Definition: DoubleAc.cpp:431
DoubleAc sin(const DoubleAc &f)
Definition: DoubleAc.cpp:383
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:616
bool GetVoltageRange(double &pmin, double &pmax)
bool GetPlaneX(const int i, double &x, double &voltage, std::string &label)
bool GetBoundingBox(double &x0, double &y0, double &z0, double &x1, double &y1, double &z1)
bool GetWire(const int i, double &x, double &y, double &diameter, double &voltage, std::string &label, double &length, double &charge, int &ntrap)
bool GetPlaneY(const int i, double &y, double &voltage, std::string &label)
bool GetTube(double &r, double &voltage, int &nEdges, std::string &label)
void SetCanvas(TCanvas *c)
Definition: ViewCell.cc:54
void SetComponent(ComponentAnalyticField *comp)
Definition: ViewCell.cc:43
PlottingEngineRoot plottingEngine