13double Sensor::m_signalConversion = ElementaryCharge;
16 : m_lastComponent(-1),
21 m_hasTransferFunction(false),
23 m_hasNoiseFunction(false),
34 m_className =
"Sensor";
40 if (i >= m_components.size()) {
41 std::cerr << m_className <<
"::GetComponent:\n";
42 std::cerr <<
" Component " << i <<
" does not exist.\n";
45 return m_components[i].comp;
49 double& ex,
double& ey,
double& ez,
double& v,
50 Medium*& medium,
int& status) {
52 ex = ey = ez = v = 0.;
59 const unsigned int nComponents = m_components.size();
60 for (
unsigned int i = 0; i < nComponents; ++i) {
61 m_components[i].comp->ElectricField(x, y, z, fx, fy, fz, p, med, stat);
76 double& ex,
double& ey,
double& ez,
Medium*& medium,
86 const unsigned int nComponents = m_components.size();
87 for (
unsigned int i = 0; i < nComponents; ++i) {
88 m_components[i].comp->ElectricField(x, y, z, fx, fy, fz, med, stat);
102 double& bx,
double& by,
double& bz,
int& status) {
107 const unsigned int nComponents = m_components.size();
108 for (
unsigned int i = 0; i < nComponents; ++i) {
109 m_components[i].comp->MagneticField(x, y, z, fx, fy, fz, status);
110 if (status != 0)
continue;
118 double& wx,
double& wy,
double& wz,
119 const std::string& label) {
122 double fx = 0., fy = 0., fz = 0.;
124 const unsigned int nElectrodes = m_electrodes.size();
125 for (
unsigned int i = 0; i < nElectrodes; ++i) {
126 if (m_electrodes[i].label == label) {
128 m_electrodes[i].comp->WeightingField(x, y, z, fx, fy, fz, label);
137 const double z,
const std::string& label) {
141 const unsigned int nElectrodes = m_electrodes.size();
142 for (
unsigned int i = 0; i < nElectrodes; ++i) {
143 if (m_electrodes[i].label == label) {
144 v += m_electrodes[i].comp->WeightingPotential(x, y, z, label);
156 if (m_lastComponent < 0)
return false;
159 m = m_components[m_lastComponent].comp->GetMedium(x, y, z);
163 const unsigned int nComponents = m_components.size();
164 for (
unsigned int i = 0; i < nComponents; ++i) {
165 m = m_components[i].comp->GetMedium(x, y, z);
177 if (!GetBoundingBox(m_xMinUser, m_yMinUser, m_zMinUser, m_xMaxUser,
178 m_yMaxUser, m_zMaxUser)) {
179 std::cerr << m_className <<
"::SetArea:\n";
180 std::cerr <<
" Bounding box is not known.\n";
184 std::cout << m_className <<
"::SetArea:\n";
185 std::cout <<
" " << m_xMinUser <<
" < x [cm] < " << m_xMaxUser <<
"\n";
186 std::cout <<
" " << m_yMinUser <<
" < y [cm] < " << m_yMaxUser <<
"\n";
187 std::cout <<
" " << m_zMinUser <<
" < z [cm] < " << m_zMaxUser <<
"\n";
188 if (std::isinf(m_xMinUser) || std::isinf(m_xMaxUser)) {
189 std::cerr << m_className <<
"::SetArea:\n";
190 std::cerr <<
" Warning: infinite x-range\n";
192 if (std::isinf(m_yMinUser) || std::isinf(m_yMaxUser)) {
193 std::cerr << m_className <<
"::SetArea:\n";
194 std::cerr <<
" Warning: infinite x-range\n";
196 if (std::isinf(m_zMinUser) || std::isinf(m_zMaxUser)) {
197 std::cerr << m_className <<
"::SetArea:\n";
198 std::cerr <<
" Warning: infinite x-range\n";
200 m_hasUserArea =
true;
205 const double xmax,
const double ymax,
const double zmax) {
207 if (fabs(xmax - xmin) < Small || fabs(ymax - ymin) < Small ||
208 fabs(zmax - zmin) < Small) {
209 std::cerr << m_className <<
"::SetArea:\n";
210 std::cerr <<
" Invalid range.\n";
233 m_hasUserArea =
true;
238 double& ymax,
double& zmax) {
266 if (!m_hasUserArea) {
268 std::cerr << m_className <<
"::IsInArea:\n";
269 std::cerr <<
" User area cannot be established.\n";
272 m_hasUserArea =
true;
275 if (x >= m_xMinUser && x <= m_xMaxUser && y >= m_yMinUser &&
276 y <= m_yMaxUser && z >= m_zMinUser && z <= m_zMaxUser) {
281 std::cout << m_className <<
"::IsInArea:\n" << std::endl;
282 std::cout <<
" (" << x <<
", " << y <<
", " << z <<
") "
289 const double x1,
const double y1,
const double z1,
290 double& xc,
double& yc,
double& zc) {
291 const unsigned int nComponents = m_components.size();
292 for (
unsigned int i = 0; i < nComponents; ++i) {
293 if (m_components[i].comp->IsWireCrossed(x0, y0, z0,
294 x1, y1, z1, xc, yc, zc)) {
302 const double y0,
double z0,
double& xw,
303 double& yw,
double& rw) {
305 const unsigned int nComponents = m_components.size();
306 for (
unsigned int i = 0; i < nComponents; ++i) {
307 if (m_components[i].comp->IsInTrapRadius(q0, x0, y0, z0, xw, yw, rw)) {
317 std::cerr << m_className <<
"::AddComponent:\n Null pointer.\n";
321 component newComponent;
322 newComponent.comp = comp;
323 m_components.push_back(newComponent);
324 if (m_components.size() == 1) m_lastComponent = 0;
330 std::cerr << m_className <<
"::AddElectrode:\n Null pointer.\n";
333 const unsigned int nElectrodes = m_electrodes.size();
334 for (
unsigned int i = 0; i < nElectrodes; ++i) {
335 if (m_electrodes[i].label == label) {
336 std::cout << m_className <<
"::AddElectrode:\n";
337 std::cout <<
" Warning: An electrode with label \"" << label
338 <<
"\" exists already.\n";
339 std::cout <<
" Weighting fields will be summed up.\n";
344 electrode newElectrode;
345 newElectrode.comp = comp;
346 newElectrode.label = label;
347 m_electrodes.push_back(newElectrode);
348 m_electrodes.back().signal.resize(m_nTimeBins);
349 m_electrodes.back().electronsignal.resize(m_nTimeBins);
350 m_electrodes.back().ionsignal.resize(m_nTimeBins);
351 std::cout << m_className <<
"::AddElectrode:\n";
352 std::cout <<
" Added readout electrode \"" << label <<
"\".\n";
353 std::cout <<
" All signals are reset.\n";
359 m_components.clear();
360 m_lastComponent = -1;
361 m_electrodes.clear();
366 m_hasUserArea =
false;
375 const unsigned int nComponents = m_components.size();
376 for (
unsigned int i = 0; i < nComponents; ++i) {
377 if (!m_components[i].comp->GetVoltageRange(umin, umax))
continue;
379 if (umin < vmin) vmin = umin;
380 if (umax > vmax) vmax = umax;
390 std::cerr << m_className <<
"::GetVoltageRange:\n";
391 std::cerr <<
" Sensor voltage range not known.\n";
397 std::cout << m_className <<
"::GetVoltageRange:\n";
398 std::cout <<
" Voltage range " << vmin <<
" < V < " << vmax <<
".\n";
405 const unsigned int nElectrodes = m_electrodes.size();
406 for (
unsigned int i = 0; i < nElectrodes; ++i) {
407 m_electrodes[i].charge = 0.;
408 for (
int j = m_nTimeBins; j--;) {
409 m_electrodes[i].signal[j] = 0.;
410 m_electrodes[i].electronsignal[j] = 0.;
411 m_electrodes[i].ionsignal[j] = 0.;
418 const double x,
const double y,
const double z,
419 const double vx,
const double vy,
const double vz) {
421 if (t < m_tStart || dt <= 0.) {
423 std::cerr << m_className <<
"::AddSignal:\n";
424 if (t < m_tStart) std::cerr <<
" Time " << t <<
" out of range.\n";
425 if (dt <= 0.) std::cerr <<
" Time step < 0.\n";
429 const int bin = int((t - m_tStart) / m_tStep);
431 if (bin < 0 || bin >= (
int)m_nTimeBins) {
433 std::cerr << m_className <<
"::AddSignal:\n";
434 std::cerr <<
" Bin " << bin <<
" out of range.\n";
438 if (m_nEvents <= 0) m_nEvents = 1;
440 double wx = 0., wy = 0., wz = 0.;
442 std::cout << m_className <<
"::AddSignal:\n";
443 std::cout <<
" Time: " << t <<
"\n";
444 std::cout <<
" Step: " << dt <<
"\n";
445 std::cout <<
" Charge: " << q <<
"\n";
446 std::cout <<
" Velocity: (" << vx <<
", " << vy <<
", " << vz <<
")\n";
448 const unsigned int nElectrodes = m_electrodes.size();
449 for (
unsigned int i = 0; i < nElectrodes; ++i) {
451 m_electrodes[i].comp->WeightingField(x, y, z, wx, wy, wz,
452 m_electrodes[i].label);
454 const double cur = -q * (wx * vx + wy * vy + wz * vz);
456 std::cout <<
" Electrode " << m_electrodes[i].label <<
":\n";
457 std::cout <<
" Weighting field: (" << wx <<
", " << wy <<
", " << wz
459 std::cout <<
" Induced charge: " << cur* dt <<
"\n";
461 double delta = m_tStart + (bin + 1) * m_tStep - t;
464 m_electrodes[i].signal[bin] += cur * delta;
466 m_electrodes[i].electronsignal[bin] += cur * delta;
468 m_electrodes[i].ionsignal[bin] += cur * delta;
472 while (delta > m_tStep && bin + j < m_nTimeBins) {
473 m_electrodes[i].signal[bin + j] += cur * m_tStep;
475 m_electrodes[i].electronsignal[bin + j] += cur * m_tStep;
477 m_electrodes[i].ionsignal[bin + j] += cur * m_tStep;
482 if (bin + j < m_nTimeBins) {
483 m_electrodes[i].signal[bin + j] += cur * delta;
485 m_electrodes[i].electronsignal[bin + j] += cur * delta;
487 m_electrodes[i].ionsignal[bin + j] += cur * delta;
491 m_electrodes[i].signal[bin] += cur * dt;
493 m_electrodes[i].electronsignal[bin] += cur * dt;
495 m_electrodes[i].ionsignal[bin] += cur * dt;
502 const double z0,
const double x1,
const double y1,
505 if (m_debug) std::cout << m_className <<
"::AddInducedCharge:\n";
506 double w0 = 0., w1 = 0.;
507 const unsigned int nElectrodes = m_electrodes.size();
508 for (
unsigned int i = 0; i < nElectrodes; ++i) {
511 .comp->WeightingPotential(x0, y0, z0, m_electrodes[i].label);
514 .comp->WeightingPotential(x1, y1, z1, m_electrodes[i].label);
515 m_electrodes[i].charge += q * (w1 - w0);
517 std::cout <<
" Electrode " << m_electrodes[i].label <<
":\n";
518 std::cout <<
" Weighting potential at (" << x0 <<
", " << y0 <<
", "
519 << z0 <<
"): " << w0 <<
"\n";
520 std::cout <<
" Weighting potential at (" << x1 <<
", " << y1 <<
", "
521 << z1 <<
"): " << w1 <<
"\n";
522 std::cout <<
" Induced charge: " << m_electrodes[i].charge <<
"\n";
528 const unsigned int nsteps) {
532 std::cerr << m_className <<
"::SetTimeWindow:\n";
533 std::cerr <<
" Starting time out of range.\n";
539 std::cerr << m_className <<
"::SetTimeWindow:\n";
540 std::cerr <<
" Number of time bins out of range.\n";
542 m_nTimeBins = nsteps;
546 std::cout << m_className <<
"::SetTimeWindow:\n";
547 std::cout <<
" " << m_tStart <<
" < t [ns] < "
548 << m_tStart + m_nTimeBins* m_tStep <<
"\n";
549 std::cout <<
" Step size: " << m_tStep <<
" ns\n";
552 std::cout << m_className <<
"::SetTimeWindow:\n";
553 std::cout <<
" Resetting all signals.\n";
554 const unsigned int nElectrodes = m_electrodes.size();
555 for (
unsigned int i = 0; i < nElectrodes; ++i) {
556 m_electrodes[i].signal.assign(m_nTimeBins, 0.);
557 m_electrodes[i].electronsignal.assign(m_nTimeBins, 0.);
558 m_electrodes[i].ionsignal.assign(m_nTimeBins, 0.);
564 const unsigned int bin) {
566 if (m_nEvents == 0)
return 0.;
567 if (bin >= m_nTimeBins)
return 0.;
569 const unsigned int nElectrodes = m_electrodes.size();
570 for (
unsigned int i = 0; i < nElectrodes; ++i) {
571 if (m_electrodes[i].label == label)
572 sig += m_electrodes[i].electronsignal[bin];
575 std::cout << m_className <<
"::GetElectronSignal:\n";
576 std::cout <<
" Electrode: " << label <<
"\n";
577 std::cout <<
" Bin: " << bin <<
"\n";
578 std::cout <<
" ElectronSignal: " << sig / m_tStep <<
"\n";
580 return m_signalConversion * sig / (m_nEvents * m_tStep);
585 if (m_nEvents == 0)
return 0.;
586 if (bin >= m_nTimeBins)
return 0.;
588 const unsigned int nElectrodes = m_electrodes.size();
589 for (
unsigned int i = 0; i < nElectrodes; ++i) {
590 if (m_electrodes[i].label == label) sig += m_electrodes[i].ionsignal[bin];
593 std::cout << m_className <<
"::GetIonSignal:\n";
594 std::cout <<
" Electrode: " << label <<
"\n";
595 std::cout <<
" Bin: " << bin <<
"\n";
596 std::cout <<
" IonSignal: " << sig / m_tStep <<
"\n";
598 return m_signalConversion * sig / (m_nEvents * m_tStep);
603 if (m_nEvents == 0)
return 0.;
604 if (bin >= m_nTimeBins)
return 0.;
606 const unsigned int nElectrodes = m_electrodes.size();
607 for (
unsigned int i = 0; i < nElectrodes; ++i) {
608 if (m_electrodes[i].label == label) sig += m_electrodes[i].signal[bin];
611 std::cout << m_className <<
"::GetSignal:\n";
612 std::cout <<
" Electrode: " << label <<
"\n";
613 std::cout <<
" Bin: " << bin <<
"\n";
614 std::cout <<
" Signal: " << sig / m_tStep <<
"\n";
616 return m_signalConversion * sig / (m_nEvents * m_tStep);
621 if (m_nEvents == 0)
return 0.;
623 const unsigned int nElectrodes = m_electrodes.size();
624 for (
unsigned int i = 0; i < nElectrodes; ++i) {
625 if (m_electrodes[i].label == label) charge += m_electrodes[i].charge;
628 std::cout << m_className <<
"::GetInducedCharge:\n";
629 std::cout <<
" Electrode: " << label <<
"\n";
630 std::cout <<
" Charge: " << charge / m_tStep <<
"\n";
633 return charge / m_nEvents;
639 std::cerr << m_className <<
"::SetTransferFunction:\n Null pointer.\n";
643 m_hasTransferFunction =
true;
644 m_transferFunctionTimes.clear();
645 m_transferFunctionValues.clear();
649 const std::vector<double>& values) {
651 if (times.empty() || values.empty()) {
652 std::cerr << m_className <<
"::SetTransferFunction:\n";
653 std::cerr <<
" Time and value vectors must not be empty.\n";
655 }
else if (times.size() != values.size()) {
656 std::cerr << m_className <<
"::SetTransferFunction:\n";
657 std::cerr <<
" Time and value vectors must have same size.\n";
660 m_transferFunctionTimes = times;
661 m_transferFunctionValues = values;
663 m_hasTransferFunction =
true;
666double Sensor::InterpolateTransferFunctionTable(
double t) {
668 if (m_transferFunctionTimes.empty() || m_transferFunctionValues.empty()) {
672 if (t < m_transferFunctionTimes.front() ||
673 t > m_transferFunctionTimes.back()) {
678 int iUp = m_transferFunctionTimes.size() - 1;
680 while (iUp - iLow > 1) {
681 iM = (iUp + iLow) >> 1;
682 if (t >= m_transferFunctionTimes[iM]) {
689 return m_transferFunctionValues[iLow] +
690 (t - m_transferFunctionTimes[iLow]) *
691 (m_transferFunctionValues[iUp] - m_transferFunctionValues[iLow]) /
692 (m_transferFunctionTimes[iUp] - m_transferFunctionTimes[iLow]);
697 if (!m_hasTransferFunction)
return 0.;
698 if (m_fTransfer)
return m_fTransfer(t);
699 return InterpolateTransferFunctionTable(t);
704 if (!m_hasTransferFunction) {
705 std::cerr << m_className <<
"::ConvoluteSignal:\n";
706 std::cerr <<
" No transfer function available.\n";
709 if (m_nEvents == 0) {
710 std::cerr << m_className <<
"::ConvoluteSignal:\n";
711 std::cerr <<
" No signals present.\n";
717 double cnvMax = 1.e10;
719 std::vector<double> cnvTab(2 * m_nTimeBins, 0.);
720 int iOffset = m_nTimeBins;
722 for (
unsigned int i = 0; i < m_nTimeBins; ++i) {
724 double t = -i * m_tStep;
725 if (t < cnvMin || t > cnvMax) {
726 cnvTab[iOffset - i] = 0.;
727 }
else if (m_fTransfer) {
728 cnvTab[iOffset - i] = m_fTransfer(t);
730 cnvTab[iOffset - i] = InterpolateTransferFunctionTable(t);
735 if (t < cnvMin || t > cnvMax) {
736 cnvTab[iOffset + i] = 0.;
737 }
else if (m_fTransfer) {
738 cnvTab[iOffset + i] = m_fTransfer(t);
740 cnvTab[iOffset + i] = InterpolateTransferFunctionTable(t);
744 std::vector<double> tmpSignal(m_nTimeBins, 0.);
746 const unsigned int nElectrodes = m_electrodes.size();
747 for (
unsigned int i = 0; i < nElectrodes; ++i) {
748 for (
unsigned int j = 0; j < m_nTimeBins; ++j) {
750 for (
unsigned int k = 0; k < m_nTimeBins; ++k) {
752 m_tStep * cnvTab[iOffset + j - k] * m_electrodes[i].signal[k];
755 m_electrodes[i].signal = tmpSignal;
762 if (m_nEvents == 0) {
763 std::cerr << m_className <<
"::IntegrateSignal:\n";
764 std::cerr <<
" No signals present.\n";
768 const unsigned int nElectrodes = m_electrodes.size();
769 for (
unsigned int i = 0; i < nElectrodes; ++i) {
770 for (
unsigned int j = 0; j < m_nTimeBins; ++j) {
771 m_electrodes[i].signal[j] *= m_tStep;
772 m_electrodes[i].electronsignal[j] *= m_tStep;
773 m_electrodes[i].ionsignal[j] *= m_tStep;
775 m_electrodes[i].signal[j] += m_electrodes[i].signal[j - 1];
776 m_electrodes[i].electronsignal[j] +=
777 m_electrodes[i].electronsignal[j - 1];
778 m_electrodes[i].ionsignal[j] += m_electrodes[i].ionsignal[j - 1];
788 std::cerr << m_className <<
"::SetNoiseFunction:\n";
789 std::cerr <<
" Function pointer is null.\n";
793 m_hasNoiseFunction =
true;
798 if (!m_hasNoiseFunction) {
799 std::cerr << m_className <<
"::AddNoise:\n";
800 std::cerr <<
" Noise function is not defined.\n";
803 if (m_nEvents == 0) m_nEvents = 1;
805 const unsigned int nElectrodes = m_electrodes.size();
806 for (
unsigned int i = 0; i < nElectrodes; ++i) {
807 for (
unsigned int j = 0; j < m_nTimeBins; ++j) {
808 const double t = m_tStart + (j + 0.5) * m_tStep;
809 const double noise = m_fNoise(t);
810 if (total) m_electrodes[i].signal[j] += noise;
811 if (electron) m_electrodes[i].electronsignal[j] += noise;
812 if (ion) m_electrodes[i].ionsignal[j] += noise;
818 const std::string& label,
int& n) {
821 m_thresholdCrossings.clear();
822 m_thresholdLevel = thr;
827 if (m_nEvents == 0) {
828 std::cerr << m_className <<
"::ComputeThresholdCrossings:\n";
829 std::cerr <<
" No signals present.\n";
834 std::vector<double> signal(m_nTimeBins, 0.);
836 bool foundLabel =
false;
837 const unsigned int nElectrodes = m_electrodes.size();
838 for (
unsigned int j = 0; j < nElectrodes; ++j) {
839 if (m_electrodes[j].label == label) {
841 for (
unsigned int i = 0; i < m_nTimeBins; ++i) {
842 signal[i] += m_electrodes[j].signal[i];
847 std::cerr << m_className <<
"::ComputeThresholdCrossings:\n";
848 std::cerr <<
" Electrode " << label <<
" not found.\n";
851 const double scale = m_signalConversion / (m_nEvents * m_tStep);
852 for (
unsigned int i = 0; i < m_nTimeBins; ++i) signal[i] *= scale;
855 double vMin = signal[0];
856 double vMax = signal[0];
857 for (
unsigned int i = 0; i < m_nTimeBins; ++i) {
858 if (signal[i] < vMin) vMin = signal[i];
859 if (signal[i] > vMax) vMax = signal[i];
861 if (thr < vMin && thr > vMax) {
863 std::cout << m_className <<
"::ComputeThresholdCrossings:\n";
864 std::cout <<
" Threshold outside the range [" << vMin <<
", " << vMax
874 while (rise || fall) {
877 std::cout << m_className <<
"::ComputeThresholdCrossings:\n";
878 std::cout <<
" Hunting for rising edges.\n";
880 std::cout << m_className <<
"::ComputeThresholdCrossings:\n";
881 std::cout <<
" Hunting for falling edges.\n";
885 std::vector<double> times;
886 std::vector<double> values;
887 times.push_back(m_tStart);
888 values.push_back(signal[0]);
891 for (
unsigned int i = 1; i < m_nTimeBins; ++i) {
893 const double tNew = m_tStart + i * m_tStep;
894 const double vNew = signal[i];
896 if ((rise && vNew > values.back()) || (fall && vNew < values.back())) {
897 times.push_back(tNew);
898 values.push_back(vNew);
901 }
else if ((values[0] - thr) * (thr - values.back()) >= 0. &&
902 nValues > 1 && ((rise && values.back() > values[0]) ||
903 (fall && values.back() < values[0]))) {
906 thresholdCrossing newCrossing;
907 newCrossing.time = tcr;
908 newCrossing.rise = rise;
909 m_thresholdCrossings.push_back(newCrossing);
912 times.push_back(tNew);
913 values.push_back(vNew);
919 times.push_back(tNew);
920 values.push_back(vNew);
925 if ((values[0] - thr) * (thr - values.back()) >= 0. && nValues > 1 &&
926 ((rise && values.back() > values[0]) ||
927 (fall && values.back() < values[0]))) {
929 thresholdCrossing newCrossing;
930 newCrossing.time = tcr;
931 newCrossing.rise = rise;
932 m_thresholdCrossings.push_back(newCrossing);
941 n = m_thresholdCrossings.size();
944 std::cout << m_className <<
"::ComputeThresholdCrossings:\n";
945 std::cout <<
" Found " << n <<
" crossings.\n";
946 if (n > 0) std::cout <<
" Time [ns] Direction\n";
947 for (
int i = 0; i < n; ++i) {
948 std::cout <<
" " << m_thresholdCrossings[i].time <<
" ";
949 if (m_thresholdCrossings[i].rise) {
950 std::cout <<
"rising\n";
952 std::cout <<
"falling\n";
961 double& level,
bool& rise)
const {
963 level = m_thresholdLevel;
965 if (i >= m_thresholdCrossings.size()) {
966 std::cerr << m_className <<
"::GetThresholdCrossing:\n";
967 std::cerr <<
" Index (" << i <<
") out of range.\n";
968 time = m_tStart + m_nTimeBins * m_tStep;
972 time = m_thresholdCrossings[i].time;
973 rise = m_thresholdCrossings[i].rise;
977bool Sensor::GetBoundingBox(
double& xmin,
double& ymin,
double& zmin,
978 double& xmax,
double& ymax,
double& zmax) {
983 double x0, y0, z0, x1, y1, z1;
984 const unsigned int nComponents = m_components.size();
985 for (
unsigned int i = 0; i < nComponents; ++i) {
986 if (!m_components[i].comp->GetBoundingBox(x0, y0, z0, x1, y1, z1))
continue;
988 if (x0 < xmin) xmin = x0;
989 if (y0 < ymin) ymin = y0;
990 if (z0 < zmin) zmin = z0;
991 if (x1 > xmax) xmax = x1;
992 if (y1 > ymax) ymax = y1;
993 if (z1 > zmax) zmax = z1;
1007 std::cerr << m_className <<
"::GetBoundingBox:\n";
1008 std::cerr <<
" Sensor bounding box not known.\n";
1019 std::cout << m_className <<
"::GetBoundingBox:\n";
1020 std::cout <<
" " << xmin <<
" < x [cm] < " << xmax <<
"\n";
1021 std::cout <<
" " << ymin <<
" < y [cm] < " << ymax <<
"\n";
1022 std::cout <<
" " << zmin <<
" < z [cm] < " << zmax <<
"\n";
Abstract base class for components.
Abstract base class for media.
void MagneticField(const double x, const double y, const double z, double &bx, double &by, double &bz, int &status)
Get the magnetic field at (x, y, z).
double GetElectronSignal(const std::string &label, const unsigned int bin)
bool GetVoltageRange(double &vmin, double &vmax)
Return the voltage range.
void SetTimeWindow(const double tstart, const double tstep, const unsigned int nsteps)
bool IsInTrapRadius(const double q0, const double x0, const double y0, const double z0, double &xw, double &yw, double &rw)
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label)
Get the weighting field at (x, y, z).
double GetTransferFunction(const double t)
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&medium, int &status)
Get the drift field and potential at (x, y, z).
bool SetArea()
Set the user area to the default.
double GetSignal(const std::string &label, const unsigned int bin)
void SetNoiseFunction(double(*f)(double t))
bool IsInArea(const double x, const double y, const double z)
Check if a point is inside the user area.
void AddElectrode(ComponentBase *comp, const std::string &label)
Add an electrode.
double GetInducedCharge(const std::string &label)
void AddNoise(const bool total=true, const bool electron=false, const bool ion=false)
void AddSignal(const double q, const double t, const double dt, const double x, const double y, const double z, const double vx, const double vy, const double vz)
double WeightingPotential(const double x, const double y, const double z, const std::string &label)
Get the weighting potential at (x, y, z).
bool ComputeThresholdCrossings(const double thr, const std::string &label, int &n)
bool GetMedium(const double x, const double y, const double z, Medium *&medium)
Get the medium at (x, y, z).
ComponentBase * GetComponent(const unsigned int componentNumber)
void Clear()
Remove all components, electrodes and reset the sensor.
void SetTransferFunction(double(*f)(double t))
bool GetThresholdCrossing(const unsigned int i, double &time, double &level, bool &rise) const
bool IsWireCrossed(const double x0, const double y0, const double z0, const double x1, const double y1, const double z1, double &xc, double &yc, double &zc)
void AddComponent(ComponentBase *comp)
Add a component.
void ClearSignal()
Reset signals and induced charges of all electrodes.
void AddInducedCharge(const double q, const double x0, const double y0, const double z0, const double x1, const double y1, const double z1)
double GetIonSignal(const std::string &label, const unsigned int bin)
bool GetArea(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Return the current user area.
double Divdif(const std::vector< double > &f, const std::vector< double > &a, int nn, double x, int mm)