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