Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ViewField.cc
Go to the documentation of this file.
1#include <iostream>
2#include <sstream>
3#include <stdio.h>
4#include <string.h>
5#include <cmath>
6
7#include <TROOT.h>
8#include <TAxis.h>
9
10#include "Plotting.hh"
11#include "Sensor.hh"
12#include "ComponentBase.hh"
13#include "ViewField.hh"
14
15namespace Garfield {
16
18 : className("ViewField"),
19 debug(false),
20 useStatus(false),
21 vBkg(0.),
22 sensor(0),
23 component(0),
24 pxmin(-1.),
25 pymin(-1.),
26 pxmax(1.),
27 pymax(1.),
28 fmin(0.),
29 fmax(100.),
30 emin(0.),
31 emax(10000.),
32 wmin(0.),
33 wmax(100.),
34 nContours(nMaxContours),
35 nSamples1d(1000),
36 nSamples2dX(200),
37 nSamples2dY(200),
38 electrode(""),
39 canvas(0),
40 hasExternalCanvas(false),
41 fPot(0),
42 fWfield(0),
43 fPotProfile(0) {
44
47}
48
50
51 if (!hasExternalCanvas && canvas != 0) delete canvas;
52 if (fPot != 0) delete fPot;
53 if (fWfield != 0) delete fWfield;
54 if (fPotProfile != 0) delete fPotProfile;
55}
56
58
59 if (s == 0) {
60 std::cerr << className << "::SetSensor:\n";
61 std::cerr << " Sensor pointer is null.\n";
62 return;
63 }
64
65 sensor = s;
66 component = 0;
67 // Get the bounding box.
68 bool ok = sensor->GetArea(pxmin, pymin, pzmin, pxmax, pymax, pzmax);
69 if (!ok) {
70 std::cerr << className << "::SetSensor:\n";
71 std::cerr << " Warning: bounding box of sensor is not defined.\n";
72 }
73 // Get the voltage range.
74 ok = sensor->GetVoltageRange(fmin, fmax);
75 if (!ok) {
76 std::cerr << className << "::SetSensor:\n";
77 std::cerr << " Warning: voltage range of sensor is not defined.\n";
78 }
79}
80
82
83 if (c == 0) {
84 std::cerr << className << "::SetComponent:\n";
85 std::cerr << " Component pointer is null.\n";
86 return;
87 }
88
89 component = c;
90 sensor = 0;
91 // Get the bounding box.
92 bool ok = component->GetBoundingBox(pxmin, pymin, pzmin, pxmax, pymax, pzmax);
93 if (!ok) {
94 std::cerr << className << "::SetComponent:\n";
95 std::cerr << " Warning: bounding box of component is not defined.\n";
96 }
97 // Get the voltage range.
98 ok = component->GetVoltageRange(fmin, fmax);
99 if (!ok) {
100 std::cerr << className << "::SetComponent:\n";
101 std::cerr << " Warning: voltage range of component is not defined.\n";
102 }
103}
104
105void ViewField::SetCanvas(TCanvas* c) {
106
107 if (c == 0) return;
108 if (!hasExternalCanvas && canvas != 0) {
109 delete canvas;
110 canvas = 0;
111 }
112 canvas = c;
113 hasExternalCanvas = true;
114}
115
116void ViewField::SetArea(double xmin, double ymin, double xmax, double ymax) {
117
118 // Check range, assign if non-null
119 if (xmin == xmax || ymin == ymax) {
120 std::cerr << className << "::SetArea:\n";
121 std::cerr << " Null area range not permitted.\n";
122 std::cerr << " " << xmin << " < x < " << xmax << "\n";
123 std::cerr << " " << ymin << " < y < " << ymax << "\n";
124 return;
125 }
126 pxmin = std::min(xmin, xmax);
127 pymin = std::min(ymin, ymax);
128 pxmax = std::max(xmin, xmax);
129 pymax = std::max(ymin, ymax);
130}
131
132void ViewField::SetVoltageRange(const double minval, const double maxval) {
133
134 fmin = std::min(minval, maxval);
135 fmax = std::max(minval, maxval);
136}
137
138void ViewField::SetElectricFieldRange(const double minval,
139 const double maxval) {
140
141 emin = std::min(minval, maxval);
142 emax = std::max(minval, maxval);
143}
144
145void ViewField::SetWeightingFieldRange(const double minval,
146 const double maxval) {
147
148 wmin = std::min(minval, maxval);
149 wmax = std::max(minval, maxval);
150}
151
153
154 if (n <= nMaxContours) {
155 nContours = n;
156 } else {
157 std::cerr << className << "::SetNumberOfContours:\n";
158 std::cerr << " Max. number of contours is " << nMaxContours << ".\n";
159 }
160}
161
163
164 const int nmin = 10;
165 const int nmax = 100000;
166
167 if (n < nmin || n > nmax) {
168 std::cerr << className << "::SetNumberOfSamples1d:\n";
169 std::cerr << " Number of points (" << n << ") out of range.\n";
170 std::cerr << " " << nmin << " <= n <= " << nmax << "\n";
171 return;
172 }
173
174 nSamples1d = n;
175}
176
177void ViewField::SetNumberOfSamples2d(const int nx, const int ny) {
178
179 const int nmin = 10;
180 const int nmax = 10000;
181 if (nx < nmin || nx > nmax) {
182 std::cerr << className << "::SetNumberOfSamples2d:\n";
183 std::cerr << " Number of x-points (" << nx << ") out of range.\n";
184 std::cerr << " " << nmin << " <= nx <= " << nmax << "\n";
185 } else {
186 nSamples2dX = nx;
187 }
188
189 if (ny < nmin || ny > nmax) {
190 std::cerr << className << "::SetNumberOfSamples2d:\n";
191 std::cerr << " Number of y-points (" << ny << ") out of range.\n";
192 std::cerr << " " << nmin << " <= ny <= " << nmax << "\n";
193 } else {
194 nSamples2dY = ny;
195 }
196}
197
198void ViewField::PlotContour(const std::string option) {
199
200 // Setup the canvas
201 if (canvas == 0) {
202 canvas = new TCanvas();
203 canvas->SetTitle("Field View");
204 if (hasExternalCanvas) hasExternalCanvas = false;
205 }
206 canvas->cd();
207 canvas->Range(pxmin, pymin, pxmax, pymax);
208
209 if (fPot == 0) CreateFunction();
210
211 int plotType = 0;
212 if (option == "v" || option == "p" || option == "phi" || option == "volt" ||
213 option == "voltage" || option == "pot" || option == "potential") {
214 fPot->SetParameter(0, -1.);
215 fPot->SetRange(pxmin, pymin, pxmax, pymax);
216 fPot->SetMinimum(fmin);
217 fPot->SetMaximum(fmax);
218 } else if (option == "e" || option == "field") {
219 fPot->SetParameter(0, 1.);
220 plotType = 1;
221 fPot->SetMinimum(emin);
222 fPot->SetMaximum(emax);
223 } else if (option == "ex") {
224 fPot->SetParameter(0, 11.);
225 plotType = 2;
226 fPot->SetMinimum(emin);
227 fPot->SetMaximum(emax);
228 } else if (option == "ey") {
229 fPot->SetParameter(0, 21.);
230 plotType = 3;
231 fPot->SetMinimum(emin);
232 fPot->SetMaximum(emax);
233 } else if (option == "ez") {
234 fPot->SetParameter(0, 31.);
235 plotType = 4;
236 fPot->SetMinimum(emin);
237 fPot->SetMaximum(emax);
238 } else {
239 std::cerr << className << "::PlotContour:\n";
240 std::cerr << " Unknown option (" << option << ")\n";
241 std::cerr << " Plotting the potential.\n";
242 fPot->SetParameter(0, -1.);
243 fPot->SetMinimum(fmin);
244 fPot->SetMaximum(fmax);
245 }
246
247 double level[nMaxContours];
248 for (int i = 0; i < nContours; ++i) {
249 if (nContours > 1) {
250 if (plotType == 0) {
251 level[i] = fmin + i * (fmax - fmin) / (nContours - 1.);
252 } else {
253 level[i] = emin + i * (emax - emin) / (nContours - 1.);
254 }
255 } else {
256 if (plotType == 0) {
257 level[i] = (fmax + fmin) / 2.;
258 } else {
259 level[i] = (emax + emin) / 2.;
260 }
261 }
262 }
263 fPot->SetContour(nContours, level);
264
265 if (debug) {
266 std::cout << className << "::PlotContour:\n";
267 std::cout << " Number of contours: " << nContours << "\n";
268 for (int i = 0; i < nContours; ++i) {
269 std::cout << " Level " << i << " = " << level[i] << "\n";
270 }
271 }
272 fPot->SetNpx(nSamples2dX);
273 fPot->SetNpy(nSamples2dY);
274 fPot->GetXaxis()->SetTitle(xLabel);
275 fPot->GetYaxis()->SetTitle(yLabel);
276 if (plotType == 0) {
277 fPot->SetTitle("Contours of the potential");
278 } else if (plotType == 1) {
279 fPot->SetTitle("Contours of the electric field");
280 } else if (plotType == 2) {
281 fPot->SetTitle("Contours of the electric field (x-component)");
282 } else if (plotType == 3) {
283 fPot->SetTitle("Contours of the electric field (y-component)");
284 } else if (plotType == 4) {
285 fPot->SetTitle("Contours of the electric field (z-component)");
286 }
287 fPot->Draw("CONT4Z");
288 canvas->Update();
289}
290
291void ViewField::PlotSurface(const std::string option) {
292
293 // Setup the canvas
294 if (canvas == 0) {
295 canvas = new TCanvas();
296 canvas->SetTitle("Field View");
297 if (hasExternalCanvas) hasExternalCanvas = false;
298 }
299 canvas->cd();
300 canvas->Range(pxmin, pymin, pxmax, pymax);
301
302 if (fPot == 0) CreateFunction();
303
304 int plotType = 0;
305 if (option == "v" || option == "p" || option == "phi" || option == "volt" ||
306 option == "voltage" || option == "pot" || option == "potential") {
307 fPot->SetParameter(0, -1.);
308 fPot->SetMinimum(fmin);
309 fPot->SetMinimum(fmax);
310 } else if (option == "e" || option == "field") {
311 fPot->SetParameter(0, 1.);
312 plotType = 1;
313 fPot->SetMinimum(emin);
314 fPot->SetMinimum(emax);
315 } else if (option == "ex") {
316 fPot->SetParameter(0, 11.);
317 plotType = 2;
318 fPot->SetMinimum(emin);
319 fPot->SetMinimum(emax);
320 } else if (option == "ey") {
321 fPot->SetParameter(0, 21.);
322 plotType = 3;
323 fPot->SetMinimum(emin);
324 fPot->SetMinimum(emax);
325 } else if (option == "ez") {
326 fPot->SetParameter(0, 31.);
327 plotType = 4;
328 fPot->SetMinimum(emin);
329 fPot->SetMinimum(emax);
330 } else {
331 std::cerr << className << "::PlotSurface:\n";
332 std::cerr << " Unknown option (" << option << ")\n";
333 std::cerr << " Plotting the potential.\n";
334 fPot->SetParameter(0, -1.);
335 fPot->SetMinimum(fmin);
336 fPot->SetMinimum(fmax);
337 }
338 fPot->SetNpx(nSamples2dX);
339 fPot->SetNpy(nSamples2dY);
340 fPot->GetXaxis()->SetTitle(xLabel);
341 fPot->GetYaxis()->SetTitle(yLabel);
342 if (plotType == 0) {
343 fPot->SetTitle("Surface plot of the potential");
344 } else if (plotType == 1) {
345 fPot->SetTitle("Surface plot of the electric field");
346 } else if (plotType == 2) {
347 fPot->SetTitle("Surface plot of the electric field (x-component)");
348 } else if (plotType == 3) {
349 fPot->SetTitle("Surface plot of the electric field (y-component)");
350 } else if (plotType == 4) {
351 fPot->SetTitle("Surface plot of the electric field (z-component)");
352 }
353 fPot->Draw("SURF4");
354 canvas->Update();
355}
356
357void ViewField::PlotProfile(const double x0, const double y0, const double z0,
358 const double x1, const double y1, const double z1,
359 const std::string option) {
360
361 // Check the distance between the two points.
362 const double d = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2) + pow(z1 - z0, 2));
363 if (d <= 0.) {
364 std::cerr << className << "::PlotProfile:\n";
365 std::cerr << " Start and end point coincide.\n";
366 return;
367 }
368
369 // Setup the canvas.
370 if (canvas == 0) {
371 canvas = new TCanvas();
372 canvas->SetTitle("Field View");
373 if (hasExternalCanvas) hasExternalCanvas = false;
374 }
375 canvas->cd();
376
377 if (fPotProfile == 0) CreateProfileFunction();
378
379 fPotProfile->SetParameter(0, x0);
380 fPotProfile->SetParameter(1, y0);
381 fPotProfile->SetParameter(2, z0);
382 fPotProfile->SetParameter(3, x1);
383 fPotProfile->SetParameter(4, y1);
384 fPotProfile->SetParameter(5, z1);
385 int plotType = 0;
386 if (option == "v" || option == "p" || option == "phi" || option == "volt" ||
387 option == "voltage" || option == "pot" || option == "potential") {
388 fPotProfile->SetParameter(6, -1.);
389 fPotProfile->SetMinimum(fmin);
390 fPotProfile->SetMaximum(fmax);
391 } else if (option == "e" || option == "field") {
392 fPotProfile->SetParameter(6, 1.);
393 plotType = 1;
394 fPotProfile->SetMinimum(emin);
395 fPotProfile->SetMaximum(emax);
396 } else if (option == "ex") {
397 fPotProfile->SetParameter(6, 11.);
398 plotType = 2;
399 fPotProfile->SetMinimum(emin);
400 fPotProfile->SetMaximum(emax);
401 } else if (option == "ey") {
402 fPotProfile->SetParameter(6, 21.);
403 plotType = 3;
404 fPotProfile->SetMinimum(emin);
405 fPotProfile->SetMaximum(emax);
406 } else if (option == "ez") {
407 fPotProfile->SetParameter(6, 31.);
408 plotType = 4;
409 fPotProfile->SetMinimum(emin);
410 fPotProfile->SetMaximum(emax);
411 } else {
412 std::cerr << className << "::PlotProfile:\n";
413 std::cerr << " Unknown option (" << option << ")\n";
414 std::cerr << " Plotting the potential.\n";
415 fPotProfile->SetParameter(6, -1.);
416 fPotProfile->SetMinimum(fmin);
417 fPotProfile->SetMaximum(fmax);
418 }
419 if (debug) {
420 std::cout << className << "::PlotProfile:\n";
421 if (plotType == 0) {
422 std::cout << " Plotting potential along\n";
423 } else {
424 std::cout << " Plotting field along\n";
425 }
426 std::cout << " (" << fPotProfile->GetParameter(0) << ", "
427 << fPotProfile->GetParameter(1) << ", "
428 << fPotProfile->GetParameter(2) << ") - ("
429 << fPotProfile->GetParameter(3) << ", "
430 << fPotProfile->GetParameter(4) << ", "
431 << fPotProfile->GetParameter(5) << ")\n";
432 }
433 fPotProfile->GetXaxis()->SetTitle("normalised distance");
434 if (plotType == 0) {
435 fPotProfile->SetTitle("Profile plot of the potential");
436 fPotProfile->GetYaxis()->SetTitle("potential [V]");
437 } else if (plotType == 1) {
438 fPotProfile->SetTitle("Profile plot of the electric field");
439 fPotProfile->GetYaxis()->SetTitle("field [V/cm]");
440 } else if (plotType == 2) {
441 fPotProfile->SetTitle("Profile plot of the electric field (x-component)");
442 fPotProfile->GetYaxis()->SetTitle("field [V/cm]");
443 } else if (plotType == 3) {
444 fPotProfile->SetTitle("Profile plot of the electric field (y-component)");
445 fPotProfile->GetYaxis()->SetTitle("field [V/cm]");
446 } else if (plotType == 4) {
447 fPotProfile->SetTitle("Profile plot of the electric field (z-component)");
448 fPotProfile->GetYaxis()->SetTitle("field [V/cm]");
449 }
450 fPotProfile->SetNpx(nSamples1d);
451 fPotProfile->Draw();
452 canvas->Update();
453}
454
455void ViewField::PlotSurfaceWeightingField(const std::string label,
456 const std::string option) {
457
458 // Setup the canvas
459 if (canvas == 0) {
460 canvas = new TCanvas();
461 canvas->SetTitle("Field View");
462 if (hasExternalCanvas) hasExternalCanvas = false;
463 }
464 canvas->cd();
465 canvas->Range(pxmin, pymin, pxmax, pymax);
466
467 electrode = label;
468
469 if (fWfield == 0) CreateFunctionWeightingField();
470
471 int plotType = 0;
472 if (option == "v" || option == "p" || option == "phi" || option == "volt" ||
473 option == "voltage" || option == "pot" || option == "potential") {
474 fWfield->SetParameter(0, -1.);
475 } else if (option == "e" || option == "field") {
476 fWfield->SetParameter(0, 1.);
477 plotType = 1;
478 } else if (option == "ex") {
479 fWfield->SetParameter(0, 11.);
480 plotType = 2;
481 } else if (option == "ey") {
482 fWfield->SetParameter(0, 21.);
483 plotType = 3;
484 } else if (option == "ez") {
485 fWfield->SetParameter(0, 31.);
486 plotType = 4;
487 } else {
488 std::cerr << className << "::PlotSurfaceWeightingField:\n";
489 std::cerr << " Unknown option (" << option << ")\n";
490 std::cerr << " Plotting the absolute value of the field.\n";
491 fWfield->SetParameter(0, 1.);
492 }
493 fWfield->SetNpx(nSamples2dX);
494 fWfield->SetNpy(nSamples2dY);
495 fWfield->GetXaxis()->SetTitle(xLabel);
496 fWfield->GetYaxis()->SetTitle(yLabel);
497 if (plotType == 0) {
498 fWfield->SetTitle("Surface plot of the weighting potential");
499 } else if (plotType == 1) {
500 fWfield->SetTitle("Surface plot of the weighting field");
501 } else if (plotType == 2) {
502 fWfield->SetTitle("Surface plot of the weighting field (x-component)");
503 } else if (plotType == 3) {
504 fWfield->SetTitle("Surface plot of the weighting field (y-component)");
505 } else if (plotType == 4) {
506 fWfield->SetTitle("Surface plot of the weighting field (z-component)");
507 }
508 fWfield->Draw("SURF4");
509 canvas->Update();
510}
511
512void ViewField::PlotContourWeightingField(const std::string label,
513 const std::string option) {
514
515 // Setup the canvas
516 if (canvas == 0) {
517 canvas = new TCanvas();
518 canvas->SetTitle("Field View");
519 if (hasExternalCanvas) hasExternalCanvas = false;
520 }
521 canvas->cd();
522 canvas->Range(pxmin, pymin, pxmax, pymax);
523
524 electrode = label;
525
526 if (fWfield == 0) CreateFunctionWeightingField();
527
528 int plotType = 0;
529 if (option == "v" || option == "p" || option == "phi" || option == "volt" ||
530 option == "voltage" || option == "pot" || option == "potential") {
531 fWfield->SetParameter(0, -1.);
532 } else if (option == "e" || option == "field") {
533 fWfield->SetParameter(0, 1.);
534 plotType = 1;
535 } else if (option == "ex") {
536 fWfield->SetParameter(0, 11.);
537 plotType = 2;
538 } else if (option == "ey") {
539 fWfield->SetParameter(0, 21.);
540 plotType = 3;
541 } else if (option == "ez") {
542 fWfield->SetParameter(0, 31.);
543 plotType = 4;
544 } else {
545 std::cerr << className << "::PlotContourWeightingField:\n";
546 std::cerr << " Unknown option (" << option << ")\n";
547 std::cerr << " Plotting the absolute value of the field.\n";
548 fWfield->SetParameter(0, 1.);
549 }
550 fWfield->SetMinimum(wmin);
551 fWfield->SetMaximum(wmax);
552
553 double level[nMaxContours];
554 for (int i = 0; i < nContours; ++i) {
555 if (nContours > 1) {
556 level[i] = i / (nContours - 1.);
557 if (plotType > 0) {
558 level[i] = wmin + (wmax - wmin) * level[i];
559 }
560 } else {
561 level[i] = 1. / 2.;
562 if (plotType > 0) {
563 level[i] *= (wmax + wmin);
564 }
565 }
566 }
567 fWfield->SetContour(nContours, level);
568
569 if (debug) {
570 std::cout << className << "::PlotContour:\n";
571 std::cout << " Number of contours: " << nContours << "\n";
572 for (int i = 0; i < nContours; ++i) {
573 std::cout << " Level " << i << " = " << level[i] << "\n";
574 }
575 }
576 fWfield->SetNpx(nSamples2dX);
577 fWfield->SetNpy(nSamples2dY);
578 fWfield->GetXaxis()->SetTitle(xLabel);
579 fWfield->GetYaxis()->SetTitle(yLabel);
580 if (plotType == 0) {
581 fWfield->SetTitle("Contours of the weighting potential");
582 } else if (plotType == 1) {
583 fWfield->SetTitle("Contours of the weighting field");
584 } else if (plotType == 2) {
585 fWfield->SetTitle("Contours of the weighting field (x-component)");
586 } else if (plotType == 3) {
587 fWfield->SetTitle("Contours of the weighting field (y-component)");
588 } else if (plotType == 4) {
589 fWfield->SetTitle("Contours of the weighting field (z-component)");
590 }
591 fWfield->Draw("CONT4Z");
592 canvas->Update();
593}
594
595void ViewField::CreateFunction() {
596
597 int idx = 0;
598 std::string fname = "fPotential_0";
599 while (gROOT->GetListOfFunctions()->FindObject(fname.c_str())) {
600 ++idx;
601 std::stringstream ss;
602 ss << "fPotential_";
603 ss << idx;
604 fname = ss.str();
605 }
606
607 fPot = new TF2(fname.c_str(), this, &ViewField::EvaluatePotential, pxmin,
608 pxmax, pymin, pymax, 1, "ViewField", "EvaluatePotential");
609}
610
611void ViewField::CreateProfileFunction() {
612
613 int idx = 0;
614 std::string fname = "fPotentialProfile_0";
615 while (gROOT->GetListOfFunctions()->FindObject(fname.c_str())) {
616 ++idx;
617 std::stringstream ss;
618 ss << "fPotentialProfile_";
619 ss << idx;
620 fname = ss.str();
621 }
622
623 const int nParameters = 7;
624 fPotProfile =
625 new TF1(fname.c_str(), this, &ViewField::EvaluatePotentialProfile, 0., 1.,
626 nParameters, "ViewField", "EvaluatePotentialProfile");
627}
628
629void ViewField::CreateFunctionWeightingField() {
630
631 int idx = 0;
632 std::string fname = "fWfield_0";
633 while (gROOT->GetListOfFunctions()->FindObject(fname.c_str())) {
634 ++idx;
635 std::stringstream ss;
636 ss << "fWfield_";
637 ss << idx;
638 fname = ss.str();
639 }
640
641 fWfield =
642 new TF2(fname.c_str(), this, &ViewField::EvaluateWeightingField, pxmin,
643 pxmax, pymin, pymax, 1, "ViewField", "EvaluateWeightingField");
644}
645
647
648 // Default projection: x-y at z=0
649 project[0][0] = 1;
650 project[1][0] = 0;
651 project[2][0] = 0;
652 project[0][1] = 0;
653 project[1][1] = 1;
654 project[2][1] = 0;
655 project[0][2] = 0;
656 project[1][2] = 0;
657 project[2][2] = 0;
658
659 // Plane description
660 plane[0] = 0;
661 plane[1] = 0;
662 plane[2] = 1;
663 plane[3] = 0;
664
665 // Prepare axis labels.
666 Labels();
667}
668
669double ViewField::EvaluatePotential(double* pos, double* par) {
670
671 if (sensor == 0 && component == 0) return 0.;
672
673 // Compute the field.
674 double ex = 0., ey = 0., ez = 0., volt = 0.;
675 int status = 0;
676 Medium* medium;
677 const double xpos =
678 project[0][0] * pos[0] + project[1][0] * pos[1] + project[2][0];
679 const double ypos =
680 project[0][1] * pos[0] + project[1][1] * pos[1] + project[2][1];
681 const double zpos =
682 project[0][2] * pos[0] + project[1][2] * pos[1] + project[2][2];
683
684 if (sensor == 0) {
685 component->ElectricField(xpos, ypos, zpos, ex, ey, ez, volt, medium,
686 status);
687 } else {
688 sensor->ElectricField(xpos, ypos, zpos, ex, ey, ez, volt, medium, status);
689 }
690 if (debug) {
691 std::cout << className << "::EvaluatePotential:\n";
692 std::cout << " At (u, v) = (" << pos[0] << ", " << pos[1] << "), "
693 << " (x,y,z) = (" << xpos << "," << ypos << "," << zpos << ")\n";
694 std::cout << " E = " << ex << ", " << ey << ", " << ez
695 << "), V = " << volt << ", status = " << status << "\n";
696 }
697
698 if (useStatus && status != 0) return vBkg;
699
700 // Select the quantity to be plotted.
701 if (par[0] > 30.) {
702 return ez;
703 } else if (par[0] > 20.) {
704 return ey;
705 } else if (par[0] > 10.) {
706 return ex;
707 } else if (par[0] > 0.) {
708 return sqrt(ex * ex + ey * ey + ez * ez);
709 }
710 // Return the potential.
711 return volt;
712}
713
714double ViewField::EvaluatePotentialProfile(double* pos, double* par) {
715
716 if (sensor == 0 && component == 0) return 0.;
717
718 // Get the start and end position.
719 const double x0 = par[0];
720 const double y0 = par[1];
721 const double z0 = par[2];
722 const double x1 = par[3];
723 const double y1 = par[4];
724 const double z1 = par[5];
725 // Compute the direction.
726 const double dx = x1 - x0;
727 const double dy = y1 - y0;
728 const double dz = z1 - z0;
729 // Get the position.
730 const double t = pos[0];
731
732 // Compute the field.
733 double ex = 0., ey = 0., ez = 0., volt = 0.;
734 int status = 0;
735 Medium* medium;
736
737 if (sensor == 0) {
738 component->ElectricField(x0 + t * dx, y0 + t * dy, z0 + t * dz, ex, ey, ez,
739 volt, medium, status);
740 } else {
741 sensor->ElectricField(x0 + t * dx, y0 + t * dy, z0 + t * dz, ex, ey, ez,
742 volt, medium, status);
743 }
744
745 if (useStatus && status != 0) volt = vBkg;
746
747 // Select the quantity to be plotted.
748 if (par[6] > 30.) {
749 return ez;
750 } else if (par[6] > 20.) {
751 return ey;
752 } else if (par[6] > 10.) {
753 return ex;
754 } else if (par[6] > 0.) {
755 return sqrt(ex * ex + ey * ey + ez * ez);
756 }
757 // Return the potential.
758 return volt;
759}
760
761double ViewField::EvaluateWeightingField(double* pos, double* par) {
762
763 if (sensor == 0 && component == 0) return 0.;
764
765 // Compute the field.
766 double ex = 0., ey = 0., ez = 0., v = 0.;
767 const double xpos =
768 project[0][0] * pos[0] + project[1][0] * pos[1] + project[2][0];
769 const double ypos =
770 project[0][1] * pos[0] + project[1][1] * pos[1] + project[2][1];
771 const double zpos =
772 project[0][2] * pos[0] + project[1][2] * pos[1] + project[2][2];
773
774 if (sensor == 0) {
775 if (par[0] > 0.) {
776 component->WeightingField(xpos, ypos, zpos, ex, ey, ez, electrode);
777 } else {
778 v = component->WeightingPotential(xpos, ypos, zpos, electrode);
779 }
780 } else {
781 if (par[0] > 0.) {
782 sensor->WeightingField(xpos, ypos, zpos, ex, ey, ez, electrode);
783 } else {
784 v = sensor->WeightingPotential(xpos, ypos, zpos, electrode);
785 }
786 }
787 if (debug) {
788 std::cout << className << "::EvaluateWeightingField:\n";
789 std::cout << " At (u, v) = (" << pos[0] << ", " << pos[1] << "), "
790 << " (x, y, z) = (" << xpos << "," << ypos << "," << zpos
791 << ")\n";
792 if (par[0] > 0.) {
793 std::cout << " E = (" << ex << ", " << ey << ", " << ez << ")\n";
794 } else {
795 std::cout << " V = " << v << "\n";
796 }
797 }
798
799 // Select the quantity to be plotted.
800 if (par[0] < 0.) {
801 return v;
802 } else if (par[0] > 30.) {
803 return ez;
804 } else if (par[0] > 20.) {
805 return ey;
806 } else if (par[0] > 10.) {
807 return ex;
808 } else {
809 return sqrt(ex * ex + ey * ey + ez * ez);
810 }
811}
812
813void ViewField::Labels() {
814
815 // Initialisation of the x-axis label
816 strcpy(xLabel, "\0");
817 char buf[100];
818
819 // x portion
820 if (fabs(project[0][0] - 1) < 1.0e-4) {
821 strcat(xLabel, "x");
822 } else if (fabs(project[0][0] + 1) < 1.0e-4) {
823 strcat(xLabel, "-x");
824 } else if (project[0][0] > 1.0e-4) {
825 sprintf(buf, "%g x", project[0][0]);
826 strcat(xLabel, buf);
827 } else if (project[0][0] < -1.0e-4) {
828 sprintf(buf, "%g x", project[0][0]);
829 strcat(xLabel, buf);
830 }
831
832 // y portion
833 if (strlen(xLabel) > 0) {
834 if (project[0][1] < -1.0e-4) {
835 strcat(xLabel, " - ");
836 } else if (project[0][1] > 1.0e-4) {
837 strcat(xLabel, " + ");
838 }
839 if (fabs(project[0][1] - 1) < 1.0e-4 || fabs(project[0][1] + 1) < 1.0e-4) {
840 strcat(xLabel, "y");
841 } else if (fabs(project[0][1]) > 1.0e-4) {
842 sprintf(buf, "%g y", fabs(project[0][1]));
843 strcat(xLabel, buf);
844 }
845 } else {
846 if (fabs(project[0][1] - 1) < 1.0e-4) {
847 strcat(xLabel, "y");
848 } else if (fabs(project[0][1] + 1) < 1.0e-4) {
849 strcat(xLabel, "-y");
850 } else if (project[0][1] > 1.0e-4) {
851 sprintf(buf, "%g y", project[0][1]);
852 strcat(xLabel, buf);
853 } else if (project[0][1] < -1.0e-4) {
854 sprintf(buf, "%g y", project[0][1]);
855 strcat(xLabel, buf);
856 }
857 }
858
859 // z portion
860 if (strlen(xLabel) > 0) {
861 if (project[0][2] < -1.0e-4) {
862 strcat(xLabel, " - ");
863 } else if (project[0][2] > 1.0e-4) {
864 strcat(xLabel, " + ");
865 }
866 if (fabs(project[0][2] - 1) < 1.0e-4 || fabs(project[0][2] + 1) < 1.0e-4) {
867 strcat(xLabel, "z");
868 } else if (fabs(project[0][2]) > 1.0e-4) {
869 sprintf(buf, "%g z", fabs(project[0][2]));
870 strcat(xLabel, buf);
871 }
872 } else {
873 if (fabs(project[0][2] - 1) < 1.0e-4) {
874 strcat(xLabel, "z");
875 } else if (fabs(project[0][2] + 1) < 1.0e-4) {
876 strcat(xLabel, "-z");
877 } else if (project[0][2] > 1.0e-4) {
878 sprintf(buf, "%g z", project[0][2]);
879 strcat(xLabel, buf);
880 } else if (project[0][2] < -1.0e-4) {
881 sprintf(buf, "%g z", project[0][2]);
882 strcat(xLabel, buf);
883 }
884 }
885
886 // Unit
887 strcat(xLabel, " [cm]");
888
889 // Initialisation of the y-axis label
890 strcpy(yLabel, "\0");
891
892 // x portion
893 if (fabs(project[1][0] - 1) < 1.0e-4) {
894 strcat(yLabel, "x");
895 } else if (fabs(project[1][0] + 1) < 1.0e-4) {
896 strcat(yLabel, "-x");
897 } else if (project[1][0] > 1.0e-4) {
898 sprintf(buf, "%g x", project[1][0]);
899 strcat(yLabel, buf);
900 } else if (project[1][0] < -1.0e-4) {
901 sprintf(buf, "%g x", project[1][0]);
902 strcat(yLabel, buf);
903 }
904
905 // y portion
906 if (strlen(yLabel) > 0) {
907 if (project[1][1] < -1.0e-4) {
908 strcat(yLabel, " - ");
909 } else if (project[1][1] > 1.0e-4) {
910 strcat(yLabel, " + ");
911 }
912 if (fabs(project[1][1] - 1) < 1.0e-4 || fabs(project[1][1] + 1) < 1.0e-4) {
913 strcat(yLabel, "y");
914 } else if (fabs(project[1][1]) > 1.0e-4) {
915 sprintf(buf, "%g y", fabs(project[1][1]));
916 strcat(yLabel, buf);
917 }
918 } else {
919 if (fabs(project[1][1] - 1) < 1.0e-4) {
920 strcat(yLabel, "y");
921 } else if (fabs(project[1][1] + 1) < 1.0e-4) {
922 strcat(yLabel, "-y");
923 } else if (project[1][1] > 1.0e-4) {
924 sprintf(buf, "%g y", project[1][1]);
925 strcat(yLabel, buf);
926 } else if (project[1][1] < -1.0e-4) {
927 sprintf(buf, "%g y", project[1][1]);
928 strcat(yLabel, buf);
929 }
930 }
931
932 // z portion
933 if (strlen(yLabel) > 0) {
934 if (project[1][2] < -1.0e-4) {
935 strcat(yLabel, " - ");
936 } else if (project[1][2] > 1.0e-4) {
937 strcat(yLabel, " + ");
938 }
939 if (fabs(project[1][2] - 1) < 1.0e-4 || fabs(project[1][2] + 1) < 1.0e-4) {
940 strcat(yLabel, "z");
941 } else if (fabs(project[1][2]) > 1.0e-4) {
942 sprintf(buf, "%g z", fabs(project[1][2]));
943 strcat(yLabel, buf);
944 }
945 } else {
946 if (fabs(project[1][2] - 1) < 1.0e-4) {
947 strcat(yLabel, "z");
948 } else if (fabs(project[1][2] + 1) < 1.0e-4) {
949 strcat(yLabel, "-z");
950 } else if (project[1][2] > 1.0e-4) {
951 sprintf(buf, "%g z", project[1][2]);
952 strcat(yLabel, buf);
953 } else if (project[1][2] < -1.0e-4) {
954 sprintf(buf, "%g z", project[1][2]);
955 strcat(yLabel, buf);
956 }
957 }
958
959 // Unit
960 strcat(yLabel, " [cm]");
961
962 // Initialisation of the y-axis label
963 strcpy(description, "\0");
964
965 // x portion
966 if (fabs(plane[0] - 1) < 1.0e-4) {
967 strcat(description, "x");
968 } else if (fabs(plane[0] + 1) < 1.0e-4) {
969 strcat(description, "-x");
970 } else if (plane[0] > 1.0e-4) {
971 sprintf(buf, "%g x", plane[0]);
972 strcat(description, buf);
973 } else if (plane[0] < -1.0e-4) {
974 sprintf(buf, "%g x", plane[0]);
975 strcat(description, buf);
976 }
977
978 // y portion
979 if (strlen(description) > 0) {
980 if (plane[1] < -1.0e-4) {
981 strcat(description, " - ");
982 } else if (plane[1] > 1.0e-4) {
983 strcat(description, " + ");
984 }
985 if (fabs(plane[1] - 1) < 1.0e-4 || fabs(plane[1] + 1) < 1.0e-4) {
986 strcat(description, "y");
987 } else if (fabs(plane[1]) > 1.0e-4) {
988 sprintf(buf, "%g y", fabs(plane[1]));
989 strcat(description, buf);
990 }
991 } else {
992 if (fabs(plane[1] - 1) < 1.0e-4) {
993 strcat(description, "y");
994 } else if (fabs(plane[1] + 1) < 1.0e-4) {
995 strcat(description, "-y");
996 } else if (plane[1] > 1.0e-4) {
997 sprintf(buf, "%g y", plane[1]);
998 strcat(description, buf);
999 } else if (plane[1] < -1.0e-4) {
1000 sprintf(buf, "%g y", plane[1]);
1001 strcat(description, buf);
1002 }
1003 }
1004
1005 // z portion
1006 if (strlen(description) > 0) {
1007 if (plane[2] < -1.0e-4) {
1008 strcat(description, " - ");
1009 } else if (plane[2] > 1.0e-4) {
1010 strcat(description, " + ");
1011 }
1012 if (fabs(plane[2] - 1) < 1.0e-4 || fabs(plane[2] + 1) < 1.0e-4) {
1013 strcat(description, "z");
1014 } else if (fabs(plane[2]) > 1.0e-4) {
1015 sprintf(buf, "%g z", fabs(plane[2]));
1016 strcat(description, buf);
1017 }
1018 } else {
1019 if (fabs(plane[2] - 1) < 1.0e-4) {
1020 strcat(description, "z");
1021 } else if (fabs(plane[2] + 1) < 1.0e-4) {
1022 strcat(description, "-z");
1023 } else if (plane[2] > 1.0e-4) {
1024 sprintf(buf, "%g z", plane[2]);
1025 strcat(description, buf);
1026 } else if (plane[2] < -1.0e-4) {
1027 sprintf(buf, "%g z", plane[2]);
1028 strcat(description, buf);
1029 }
1030 }
1031
1032 // Constant
1033 sprintf(buf, " = %g", plane[3]);
1034 strcat(description, buf);
1035
1036 if (debug) {
1037 std::cout << className << "::Labels:\n";
1038 std::cout << " x label: |" << xLabel << "|\n";
1039 std::cout << " y label: |" << yLabel << "|\n";
1040 std::cout << " plane: |" << description << "|\n";
1041 }
1042}
1043
1044void ViewField::SetPlane(const double fx, const double fy, const double fz,
1045 const double x0, const double y0, const double z0) {
1046
1047 // Calculate 2 in-plane vectors for the normal vector
1048 double fnorm = sqrt(fx * fx + fy * fy + fz * fz);
1049 if (fnorm > 0 && fx * fx + fz * fz > 0) {
1050 project[0][0] = fz / sqrt(fx * fx + fz * fz);
1051 project[0][1] = 0;
1052 project[0][2] = -fx / sqrt(fx * fx + fz * fz);
1053 project[1][0] = -fx * fy / (sqrt(fx * fx + fz * fz) * fnorm);
1054 project[1][1] = (fx * fx + fz * fz) / (sqrt(fx * fx + fz * fz) * fnorm);
1055 project[1][2] = -fy * fz / (sqrt(fx * fx + fz * fz) * fnorm);
1056 project[2][0] = x0;
1057 project[2][1] = y0;
1058 project[2][2] = z0;
1059 } else if (fnorm > 0 && fy * fy + fz * fz > 0) {
1060 project[0][0] = (fy * fy + fz * fz) / (sqrt(fy * fy + fz * fz) * fnorm);
1061 project[0][1] = -fx * fz / (sqrt(fy * fy + fz * fz) * fnorm);
1062 project[0][2] = -fy * fz / (sqrt(fy * fy + fz * fz) * fnorm);
1063 project[1][0] = 0;
1064 project[1][1] = fz / sqrt(fy * fy + fz * fz);
1065 project[1][2] = -fy / sqrt(fy * fy + fz * fz);
1066 project[2][0] = x0;
1067 project[2][1] = y0;
1068 project[2][2] = z0;
1069 } else {
1070 std::cout << className << "::SetPlane:\n";
1071 std::cout << " Normal vector has zero norm.\n";
1072 std::cout << " No new projection set.\n";
1073 }
1074
1075 // Store the plane description
1076 plane[0] = fx;
1077 plane[1] = fy;
1078 plane[2] = fz;
1079 plane[3] = fx * x0 + fy * y0 + fz * z0;
1080
1081 // Make labels to be placed along the axes
1082 Labels();
1083}
1084
1085void ViewField::Rotate(const double angle) {
1086
1087 // Rotate the axes
1088 double auxu[3], auxv[3];
1089 for (int i = 0; i < 3; ++i) {
1090 auxu[i] = cos(angle) * project[0][i] - sin(angle) * project[1][i];
1091 auxv[i] = sin(angle) * project[0][i] + cos(angle) * project[1][i];
1092 }
1093 for (int i = 0; i < 3; ++i) {
1094 project[0][i] = auxu[i];
1095 project[1][i] = auxv[i];
1096 }
1097
1098 // Make labels to be placed along the axes
1099 Labels();
1100}
1101}
DoubleAc cos(const DoubleAc &f)
Definition: DoubleAc.cpp:431
DoubleAc pow(const DoubleAc &f, double p)
Definition: DoubleAc.cpp:336
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:313
DoubleAc sin(const DoubleAc &f)
Definition: DoubleAc.cpp:383
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:616
virtual void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status)=0
virtual bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
virtual void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string label)
virtual double WeightingPotential(const double x, const double y, const double z, const std::string label)
virtual bool GetVoltageRange(double &vmin, double &vmax)=0
bool GetVoltageRange(double &vmin, double &vmax)
Definition: Sensor.cc:363
double WeightingPotential(const double x, const double y, const double z, const std::string label)
Definition: Sensor.cc:128
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string label)
Definition: Sensor.cc:110
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&medium, int &status)
Definition: Sensor.cc:44
bool GetArea(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Definition: Sensor.cc:227
void SetNumberOfContours(const int n)
Definition: ViewField.cc:152
void SetElectricFieldRange(const double minval, const double maxval)
Definition: ViewField.cc:138
double EvaluatePotentialProfile(double *pos, double *par)
Definition: ViewField.cc:714
void SetNumberOfSamples2d(const int nx, const int ny)
Definition: ViewField.cc:177
void PlotContourWeightingField(const std::string label, const std::string option)
Definition: ViewField.cc:512
void SetArea(double xmin, double ymin, double xmax, double ymax)
Definition: ViewField.cc:116
void SetComponent(ComponentBase *c)
Definition: ViewField.cc:81
double EvaluatePotential(double *pos, double *par)
Definition: ViewField.cc:669
void Rotate(double angle)
Definition: ViewField.cc:1085
void PlotSurface(const std::string option="v")
Definition: ViewField.cc:291
double EvaluateWeightingField(double *pos, double *par)
Definition: ViewField.cc:761
void SetSensor(Sensor *s)
Definition: ViewField.cc:57
void SetVoltageRange(const double minval, const double maxval)
Definition: ViewField.cc:132
void SetDefaultProjection()
Definition: ViewField.cc:646
void PlotSurfaceWeightingField(const std::string label, const std::string option)
Definition: ViewField.cc:455
void PlotProfile(const double x0, const double y0, const double z0, const double x1, const double y1, const double z1, const std::string option="v")
Definition: ViewField.cc:357
void SetWeightingFieldRange(const double minval, const double maxval)
Definition: ViewField.cc:145
void SetCanvas(TCanvas *c)
Definition: ViewField.cc:105
void SetPlane(double fx, double fy, double fz, double x0, double y0, double z0)
Definition: ViewField.cc:1044
void SetNumberOfSamples1d(const int n)
Definition: ViewField.cc:162
void PlotContour(const std::string option="v")
Definition: ViewField.cc:198
PlottingEngineRoot plottingEngine