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

Sensor More...

#include <Sensor.hh>

Public Member Functions

 Sensor ()=default
 Constructor.
 
 ~Sensor ()
 Destructor.
 
void AddComponent (Component *comp)
 Add a component.
 
size_t GetNumberOfComponents () const
 Get the number of components attached to the sensor.
 
ComponentGetComponent (const unsigned int i)
 Retrieve the pointer to a given component.
 
void EnableComponent (const unsigned int i, const bool on)
 Activate/deactivate a given component.
 
void EnableMagneticField (const unsigned int i, const bool on)
 Activate/deactivate use of the magnetic field of a given component.
 
void AddElectrode (Component *comp, const std::string &label)
 Add an electrode.
 
size_t GetNumberOfElectrodes () const
 Get the number of electrodes attached to the sensor.
 
void Clear ()
 Remove all components, electrodes and reset the sensor.
 
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).
 
void ElectricField (const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&medium, int &status)
 Get the drift field at (x, y, z).
 
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).
 
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 WeightingPotential (const double x, const double y, const double z, const std::string &label)
 Get the weighting potential at (x, y, z).
 
bool GetMedium (const double x, const double y, const double z, Medium *&medium)
 Get the medium at (x, y, z).
 
void EnableDebugging (const bool on=true)
 Switch debugging messages on/off.
 
bool SetArea ()
 Set the user area to the default.
 
bool SetArea (const double xmin, const double ymin, const double zmin, const double xmax, const double ymax, const double zmax)
 Set the user area explicitly.
 
bool GetArea (double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
 Return the current user area.
 
bool IsInArea (const double x, const double y, const double z)
 Check if a point is inside the user area.
 
bool GetVoltageRange (double &vmin, double &vmax)
 Return the voltage range.
 
void NewSignal ()
 Start a new event, when computing the average signal over multiple events.
 
void ClearSignal ()
 Reset signals and induced charges of all electrodes.
 
void SetTimeWindow (const double tstart, const double tstep, const unsigned int nsteps)
 
void GetTimeWindow (double &tstart, double &tstep, unsigned int &nsteps) const
 Retrieve the time window and binning.
 
void EnableDelayedSignal (const bool on=true)
 Compute the component of the signal due to the delayed weighting field.
 
void SetDelayedSignalTimes (const std::vector< double > &ts)
 Set the points in time at which to evaluate the delayed weighting field.
 
void SetDelayedSignalAveragingOrder (const unsigned int navg)
 
void SetSignal (const std::string &label, const unsigned int bin, const double signal)
 Set/override the signal in a given time bin explicitly.
 
double GetSignal (const std::string &label, const unsigned int bin)
 Retrieve the total signal for a given electrode and time bin.
 
double GetSignal (const std::string &label, const unsigned int bin, const int comp)
 Retrieve the electron signal for a given electrode and time bin.
 
double GetPromptSignal (const std::string &label, const unsigned int bin)
 Retrieve the prompt signal for a given electrode and time bin.
 
double GetDelayedSignal (const std::string &label, const unsigned int bin)
 Retrieve the delayed signal for a given electrode and time bin.
 
double GetElectronSignal (const std::string &label, const unsigned int bin)
 Retrieve the electron signal for a given electrode and time bin.
 
double GetIonSignal (const std::string &label, const unsigned int bin)
 Retrieve the ion or hole signal for a given electrode and time bin.
 
double GetDelayedElectronSignal (const std::string &label, const unsigned int bin)
 Retrieve the delayed electron signal for a given electrode and time bin.
 
double GetDelayedIonSignal (const std::string &label, const unsigned int bin)
 Retrieve the delayed ion/hole signal for a given electrode and time bin.
 
double GetInducedCharge (const std::string &label)
 Calculated using the weighting potentials at the start and end points.
 
void SetTransferFunction (double(*f)(double t))
 Set the function to be used for evaluating the transfer function.
 
void SetTransferFunction (const std::vector< double > &times, const std::vector< double > &values)
 Set the points to be used for interpolating the transfer function.
 
void SetTransferFunction (Shaper &shaper)
 Set the transfer function using a Shaper object.
 
double GetTransferFunction (const double t)
 Evaluate the transfer function at a given time.
 
void PrintTransferFunction ()
 Print some information about the presently set transfer function.
 
void EnableTransferFunctionCache (const bool on=true)
 
bool ConvoluteSignal (const std::string &label, const bool fft=false)
 
bool ConvoluteSignals (const bool fft=false)
 Convolute all induced currents with the transfer function.
 
bool IntegrateSignal (const std::string &label)
 Replace the signal on a given electrode by its integral.
 
bool IntegrateSignals ()
 Replace the signals on all electrodes curve by their integrals.
 
bool IsIntegrated (const std::string &label) const
 Return whether the signal has been integrated/convoluted.
 
bool DelayAndSubtractFraction (const double td, const double f)
 
void SetNoiseFunction (double(*f)(double t))
 Set the function to be used for evaluating the noise component.
 
void AddNoise (const bool total=true, const bool electron=false, const bool ion=false)
 Add noise to the induced signal.
 
void AddWhiteNoise (const std::string &label, const double enc, const bool poisson=true, const double q0=1.)
 
void AddWhiteNoise (const double enc, const bool poisson=true, const double q0=1.)
 Add white noise to the induced signals on all electrodes.
 
bool ComputeThresholdCrossings (const double thr, const std::string &label, int &n)
 
size_t GetNumberOfThresholdCrossings () const
 
bool GetThresholdCrossing (const unsigned int i, double &time, double &level, bool &rise) const
 
void AddSignal (const double q, const double t0, const double t1, const double x0, const double y0, const double z0, const double x1, const double y1, const double z1, const bool integrateWeightingField, const bool useWeightingPotential=false)
 Add the signal from a charge-carrier step.
 
void AddSignal (const double q, const std::vector< double > &ts, const std::vector< std::array< double, 3 > > &xs, const std::vector< std::array< double, 3 > > &vs, const std::vector< double > &ns, const int navg, const bool useWeightingPotential=false)
 Add the signal from a drift line.
 
void ExportSignal (const std::string &label, const std::string &filename)
 Exporting induced signal to a csv file.
 
void AddInducedCharge (const double q, const double x0, const double y0, const double z0, const double x1, const double y1, const double z1)
 Add the induced charge from a charge carrier drift between two points.
 
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, const bool centre, double &rc)
 
bool IsInTrapRadius (const double q0, const double x0, const double y0, const double z0, double &xw, double &yw, double &rw)
 
double IntegrateFluxLine (const double x0, const double y0, const double z0, const double x1, const double y1, const double z1, const double xp, const double yp, const double zp, const unsigned int nI, const int isign=0)
 
double GetTotalInducedCharge (const std::string label)
 

Detailed Description

Sensor

Definition at line 17 of file Sensor.hh.

Constructor & Destructor Documentation

◆ Sensor()

Garfield::Sensor::Sensor ( )
default

Constructor.

◆ ~Sensor()

Garfield::Sensor::~Sensor ( )
inline

Destructor.

Definition at line 22 of file Sensor.hh.

22{}

Member Function Documentation

◆ AddComponent()

void Garfield::Sensor::AddComponent ( Component comp)

Add a component.

Definition at line 316 of file Sensor.cc.

316 {
317 if (!cmp) {
318 std::cerr << m_className << "::AddComponent: Null pointer.\n";
319 return;
320 }
321
322 m_components.push_back(std::make_tuple(cmp, true, true));
323}

Referenced by GarfieldPhysics::InitializePhysics(), main(), and Garfield::ViewField::PlotFieldLines().

◆ AddElectrode()

void Garfield::Sensor::AddElectrode ( Component comp,
const std::string &  label 
)

Add an electrode.

Definition at line 349 of file Sensor.cc.

349 {
350 if (!cmp) {
351 std::cerr << m_className << "::AddElectrode: Null pointer.\n";
352 return;
353 }
354 for (const auto& electrode : m_electrodes) {
355 if (electrode.label == label) {
356 std::cout << m_className << "::AddElectrode:\n"
357 << " Warning: An electrode with label \"" << label
358 << "\" exists already. Weighting fields will be summed up.\n";
359 break;
360 }
361 }
362
363 Electrode electrode;
364 electrode.comp = cmp;
365 electrode.label = label;
366 electrode.signal.assign(m_nTimeBins, 0.);
367 electrode.electronSignal.assign(m_nTimeBins, 0.);
368 electrode.ionSignal.assign(m_nTimeBins, 0.);
369 electrode.delayedSignal.assign(m_nTimeBins, 0.);
370 electrode.delayedElectronSignal.assign(m_nTimeBins, 0.);
371 electrode.delayedIonSignal.assign(m_nTimeBins, 0.);
372 m_electrodes.push_back(std::move(electrode));
373 std::cout << m_className << "::AddElectrode:\n"
374 << " Added readout electrode \"" << label << "\".\n"
375 << " All signals are reset.\n";
376 ClearSignal();
377}
void ClearSignal()
Reset signals and induced charges of all electrodes.
Definition: Sensor.cc:429

Referenced by main().

◆ AddInducedCharge()

void Garfield::Sensor::AddInducedCharge ( const double  q,
const double  x0,
const double  y0,
const double  z0,
const double  x1,
const double  y1,
const double  z1 
)

Add the induced charge from a charge carrier drift between two points.

Definition at line 798 of file Sensor.cc.

800 {
801 if (m_debug) std::cout << m_className << "::AddInducedCharge:\n";
802 for (auto& electrode : m_electrodes) {
803 // Calculate the weighting potential at the starting point.
804 auto cmp = electrode.comp;
805 const double w0 = cmp->WeightingPotential(x0, y0, z0, electrode.label);
806 // Calculate the weighting potential at the end point.
807 const double w1 = cmp->WeightingPotential(x1, y1, z1, electrode.label);
808 electrode.charge += q * (w1 - w0);
809 if (m_debug) {
810 std::cout << " Electrode " << electrode.label << ":\n"
811 << " Weighting potential at (" << x0 << ", " << y0 << ", "
812 << z0 << "): " << w0 << "\n"
813 << " Weighting potential at (" << x1 << ", " << y1 << ", "
814 << z1 << "): " << w1 << "\n"
815 << " Induced charge: " << electrode.charge << "\n";
816 }
817 }
818}

◆ AddNoise()

void Garfield::Sensor::AddNoise ( const bool  total = true,
const bool  electron = false,
const bool  ion = false 
)

Add noise to the induced signal.

Definition at line 1309 of file Sensor.cc.

1309 {
1310 if (!m_fNoise) {
1311 std::cerr << m_className << "::AddNoise: Noise function not set.\n";
1312 return;
1313 }
1314 if (m_nEvents == 0) m_nEvents = 1;
1315
1316 for (auto& electrode : m_electrodes) {
1317 double t = m_tStart + 0.5 * m_tStep;
1318 for (unsigned int j = 0; j < m_nTimeBins; ++j) {
1319 const double noise = m_fNoise(t);
1320 if (total) electrode.signal[j] += noise;
1321 if (electron) electrode.electronSignal[j] += noise;
1322 if (ion) electrode.ionSignal[j] += noise;
1323 t += m_tStep;
1324 }
1325 }
1326}

◆ AddSignal() [1/2]

void Garfield::Sensor::AddSignal ( const double  q,
const double  t0,
const double  t1,
const double  x0,
const double  y0,
const double  z0,
const double  x1,
const double  y1,
const double  z1,
const bool  integrateWeightingField,
const bool  useWeightingPotential = false 
)

Add the signal from a charge-carrier step.

Definition at line 452 of file Sensor.cc.

456 {
457 if (m_debug) std::cout << m_className << "::AddSignal: ";
458 // Get the time bin.
459 if (t0 < m_tStart) {
460 if (m_debug) std::cout << "Time " << t0 << " out of range.\n";
461 return;
462 }
463 const double dt = t1 - t0;
464 if (dt < Small) {
465 if (m_debug) std::cout << "Time step too small.\n";
466 return;
467 }
468 const double invdt = 1. / dt;
469
470 const int bin = int((t0 - m_tStart) / m_tStep);
471 // Check if the starting time is outside the range
472 if (bin < 0 || bin >= (int)m_nTimeBins) {
473 if (m_debug) std::cout << "Bin " << bin << " out of range.\n";
474 return;
475 }
476 if (m_nEvents <= 0) m_nEvents = 1;
477 const bool electron = q < 0;
478 const double dx = x1 - x0;
479 const double dy = y1 - y0;
480 const double dz = z1 - z0;
481 const double vx = dx * invdt;
482 const double vy = dy * invdt;
483 const double vz = dz * invdt;
484 if (m_debug) {
485 std::cout << " Time: " << t0 << "\n"
486 << " Step: " << dt << "\n"
487 << " Charge: " << q << "\n"
488 << " Velocity: (" << vx << ", " << vy << ", " << vz << ")\n";
489 }
490 // Locations and weights for 6-point Gaussian integration
491 constexpr double tg[6] = {-0.932469514203152028, -0.661209386466264514,
492 -0.238619186083196909, 0.238619186083196909,
493 0.661209386466264514, 0.932469514203152028};
494 constexpr double wg[6] = {0.171324492379170345, 0.360761573048138608,
495 0.467913934572691047, 0.467913934572691047,
496 0.360761573048138608, 0.171324492379170345};
497 for (auto& electrode : m_electrodes) {
498 const std::string lbl = electrode.label;
499 if (m_debug) std::cout << " Electrode " << electrode.label << ":\n";
500 // Induced current.
501 double current = 0.;
502 if (useWeightingPotential) {
503 const double w0 = electrode.comp->WeightingPotential(x0, y0, z0, lbl);
504 const double w1 = electrode.comp->WeightingPotential(x1, y1, z1, lbl);
505 current = q * (w1 - w0) * invdt;
506 if (m_debug) {
507 std::cout << " Weighting potentials: " << w0 << ", " << w1 << "\n";
508 }
509 } else {
510 double wx = 0., wy = 0., wz = 0.;
511 // Calculate the weighting field for this electrode.
512 if (integrateWeightingField) {
513 for (size_t j = 0; j < 6; ++j) {
514 const double s = 0.5 * (1. + tg[j]);
515 const double x = x0 + s * dx;
516 const double y = y0 + s * dy;
517 const double z = z0 + s * dz;
518 double fx = 0., fy = 0., fz = 0.;
519 electrode.comp->WeightingField(x, y, z, fx, fy, fz, lbl);
520 wx += wg[j] * fx;
521 wy += wg[j] * fy;
522 wz += wg[j] * fz;
523 }
524 wx *= 0.5;
525 wy *= 0.5;
526 wz *= 0.5;
527 } else {
528 const double x = x0 + 0.5 * dx;
529 const double y = y0 + 0.5 * dy;
530 const double z = z0 + 0.5 * dz;
531 electrode.comp->WeightingField(x, y, z, wx, wy, wz, lbl);
532 }
533 if (m_debug) {
534 std::cout << " Weighting field: (" << wx << ", " << wy << ", " << wz
535 << ")\n";
536 }
537 // Calculate the induced current.
538 current = -q * (wx * vx + wy * vy + wz * vz);
539 }
540 if (m_debug) std::cout << " Induced charge: " << current * dt << "\n";
541 double delta = m_tStart + (bin + 1) * m_tStep - t0;
542 // Check if the provided timestep extends over more than one time bin
543 if (dt > delta) {
544 FillBin(electrode, bin, current * delta, electron, false);
545 delta = dt - delta;
546 unsigned int j = 1;
547 while (delta > m_tStep && bin + j < m_nTimeBins) {
548 FillBin(electrode, bin + j, current * m_tStep, electron, false);
549 delta -= m_tStep;
550 ++j;
551 }
552 if (bin + j < m_nTimeBins) {
553 FillBin(electrode, bin + j, current * delta, electron, false);
554 }
555 } else {
556 FillBin(electrode, bin, current * dt, electron, false);
557 }
558 }
559 if (!m_delayedSignal) return;
560 if (m_delayedSignalTimes.empty()) return;
561 const size_t nd = m_delayedSignalTimes.size();
562 // Establish the points in time at which we evaluate the delayed signal.
563 std::vector<double> td(nd);
564 for (size_t i = 0; i < nd; ++i) {
565 td[i] = t0 + m_delayedSignalTimes[i];
566 }
567 // Calculate the signals for each electrode.
568 for (auto& electrode : m_electrodes) {
569 const std::string lbl = electrode.label;
570 std::vector<double> id(nd, 0.);
571 if (useWeightingPotential) {
572 // Using the weighting potential.
573 double chargeHolder = 0.;
574 double currentHolder = 0.;
575 int binHolder = 0;
576 // Loop over each time in the given vector of delayed times.
577 for (size_t i = 0; i < nd; ++i) {
578 double delayedtime = m_delayedSignalTimes[i] - t0; // t - t0
579 if (delayedtime < 0) continue;
580 // Find bin that needs to be filled.
581 int bin2 = int((m_delayedSignalTimes[i] - m_tStart) / m_tStep);
582 // Compute induced charge
583 double dp0 = electrode.comp->DelayedWeightingPotential(
584 x0, y0, z0, delayedtime, lbl);
585 double dp1 = electrode.comp->DelayedWeightingPotential(
586 x1, y1, z1, delayedtime, lbl);
587
588 double charge = q * (dp1 - dp0);
589 // In very rare cases the result is infinity. We do not let this
590 // contribute.
591 if (std::isnan(charge)) {
592 charge = 0.;
593 }
594 // Calculate induced current based on the induced charge.
595 if (i > 0) {
596 // Time difference between previous entry.
597 double dtt = m_delayedSignalTimes[i] - m_delayedSignalTimes[i - 1];
598 // Induced current
599 double current2 = m_tStep * (charge - chargeHolder) / dtt;
600 // Fill bins
601 if (std::abs(current2) < 1e-16) current2 = 0.;
602 electrode.delayedSignal[bin2] += current2;
603 electrode.signal[bin2] += current2;
604 // Linear interpolation if the current is calculated from the induced
605 // charge of two non-subsequent bins.
606 if (binHolder > 0 && binHolder + 1 < bin2) {
607 const int diffBin = bin2 - binHolder;
608 for (int j = binHolder + 1; j < bin2; j++) {
609 electrode.delayedSignal[j] +=
610 (j - binHolder) * (current2 - currentHolder) / diffBin +
611 currentHolder;
612 electrode.signal[j] +=
613 (j - binHolder) * (current2 - currentHolder) / diffBin +
614 currentHolder;
615 }
616 }
617 currentHolder = current2;
618 }
619 // Hold information for next current calculation and interpolation.
620 binHolder = bin2;
621 chargeHolder = charge;
622 }
623 } else {
624 // Using the weighting field.
625 for (size_t i = 0; i < nd; ++i) {
626 // Integrate over the drift line segment.
627 const double step = std::min(m_delayedSignalTimes[i], dt);
628 const double scale = step / dt;
629 double sum = 0.;
630 for (size_t j = 0; j < 6; ++j) {
631 double s = 0.5 * (1. + tg[j]);
632 const double t = m_delayedSignalTimes[i] - s * step;
633 s *= scale;
634 const double x = x0 + s * dx;
635 const double y = y0 + s * dy;
636 const double z = z0 + s * dz;
637 // Calculate the delayed weighting field.
638 double wx = 0., wy = 0., wz = 0.;
639 electrode.comp->DelayedWeightingField(x, y, z, t, wx, wy, wz, lbl);
640 sum += (wx * vx + wy * vy + wz * vz) * wg[j];
641 }
642 id[i] = -q * 0.5 * sum * step;
643 }
644 FillSignal(electrode, q, td, id, m_nAvgDelayedSignal, true);
645 }
646 }
647}

◆ AddSignal() [2/2]

void Garfield::Sensor::AddSignal ( const double  q,
const std::vector< double > &  ts,
const std::vector< std::array< double, 3 > > &  xs,
const std::vector< std::array< double, 3 > > &  vs,
const std::vector< double > &  ns,
const int  navg,
const bool  useWeightingPotential = false 
)

Add the signal from a drift line.

Definition at line 649 of file Sensor.cc.

653 {
654 // Don't do anything if there are no points on the signal.
655 if (ts.size() < 2) return;
656 if (ts.size() != xs.size() || ts.size() != vs.size()) {
657 std::cerr << m_className << "::AddSignal: Mismatch in vector size.\n";
658 return;
659 }
660 const bool aval = ns.size() == ts.size();
661 const size_t nPoints = ts.size();
662 if (m_debug) {
663 std::cout << m_className << "::AddSignal: Adding a " << nPoints
664 << "-vector (charge " << q << ").\n";
665 }
666
667 if (m_nEvents <= 0) m_nEvents = 1;
668 for (auto& electrode : m_electrodes) {
669 const std::string label = electrode.label;
670 std::vector<double> signal(nPoints, 0.);
671 for (size_t i = 0; i < nPoints; ++i) {
672 const auto& x = xs[i];
673 const auto& v = vs[i];
674 if (useWeightingPotential) {
675 const double dt = i < nPoints - 1 ? ts[i + 1] - ts[i] : 0.;
676
677 const double dx = dt * v[0];
678 const double dy = dt * v[1];
679 const double dz = dt * v[2];
680
681 const double x0 = x[0] - 0.5 * dx;
682 const double y0 = x[1] - 0.5 * dy;
683 const double z0 = x[2] - 0.5 * dz;
684
685 const double x1 = x[0] + 0.5 * dx;
686 const double y1 = x[1] + 0.5 * dy;
687 const double z1 = x[2] + 0.5 * dz;
688
689 const double w0 = electrode.comp->WeightingPotential(x0, y0, z0, label);
690 const double w1 = electrode.comp->WeightingPotential(x1, y1, z1, label);
691 const double charge = q * (w1 - w0);
692 const double current = charge / dt;
693
694 signal[i] = -current;
695 if (aval) signal[i] *= ns[i];
696 } else {
697 // Calculate the weighting field at this point.
698 double wx = 0., wy = 0., wz = 0.;
699 electrode.comp->WeightingField(x[0], x[1], x[2], wx, wy, wz, label);
700 // Calculate the induced current at this point.
701 signal[i] = -q * (v[0] * wx + v[1] * wy + v[2] * wz);
702 if (aval) signal[i] *= ns[i];
703 }
704 }
705 FillSignal(electrode, q, ts, signal, navg);
706 }
707
708 if (!m_delayedSignal) return;
709 if (m_delayedSignalTimes.empty()) return;
710 // Locations and weights for 6-point Gaussian integration
711 constexpr double tg[6] = {-0.932469514203152028, -0.661209386466264514,
712 -0.238619186083196909, 0.238619186083196909,
713 0.661209386466264514, 0.932469514203152028};
714 constexpr double wg[6] = {0.171324492379170345, 0.360761573048138608,
715 0.467913934572691047, 0.467913934572691047,
716 0.360761573048138608, 0.171324492379170345};
717 const size_t nd = m_delayedSignalTimes.size();
718 for (size_t k = 0; k < nPoints - 1; ++k) {
719 const double t0 = ts[k];
720 const double t1 = ts[k + 1];
721 const double dt = t1 - t0;
722 if (dt < Small) continue;
723 const auto& x0 = xs[k];
724 const auto& x1 = xs[k + 1];
725 const auto& v = vs[k];
726 std::vector<double> td(nd);
727 for (size_t i = 0; i < nd; ++i) {
728 td[i] = t0 + m_delayedSignalTimes[i];
729 }
730 // Calculate the signals for each electrode.
731 for (auto& electrode : m_electrodes) {
732 const std::string lbl = electrode.label;
733 std::vector<double> id(nd, 0.);
734 for (size_t i = 0; i < nd; ++i) {
735 // Integrate over the drift line segment.
736 const double step = std::min(m_delayedSignalTimes[i], dt);
737 const double scale = step / dt;
738 const double dx = scale * (x1[0] - x0[0]);
739 const double dy = scale * (x1[1] - x0[1]);
740 const double dz = scale * (x1[2] - x0[2]);
741 double sum = 0.;
742 for (size_t j = 0; j < 6; ++j) {
743 const double f = 0.5 * (1. + tg[j]);
744 const double t = m_delayedSignalTimes[i] - f * step;
745 // Calculate the delayed weighting field.
746 double wx = 0., wy = 0., wz = 0.;
747 electrode.comp->DelayedWeightingField(x0[0] + f * dx, x0[1] + f * dy,
748 x0[2] + f * dz, t, wx, wy, wz,
749 lbl);
750 sum += (wx * v[0] + wy * v[1] + wz * v[2]) * wg[j];
751 }
752 id[i] = -q * 0.5 * sum * step;
753 }
754 FillSignal(electrode, q, td, id, m_nAvgDelayedSignal, true);
755 }
756 }
757}

◆ AddWhiteNoise() [1/2]

void Garfield::Sensor::AddWhiteNoise ( const double  enc,
const bool  poisson = true,
const double  q0 = 1. 
)

Add white noise to the induced signals on all electrodes.

Definition at line 1375 of file Sensor.cc.

1376 {
1377 if (!m_fTransfer && !m_shaper && m_fTransferTab.empty()) {
1378 std::cerr << m_className << "::AddWhiteNoise: Transfer function not set.\n";
1379 return;
1380 }
1381 if (m_nEvents == 0) m_nEvents = 1;
1382
1383 const double f2 = TransferFunctionSq();
1384 if (f2 < 0.) {
1385 std::cerr << m_className << "::AddWhiteNoise:\n"
1386 << " Could not calculate transfer function integral.\n";
1387 return;
1388 }
1389
1390 if (poisson) {
1391 // Frequency of random delta pulses to model noise.
1392 const double nu = (enc * enc / (q0 * q0)) / f2;
1393 // Average number of delta pulses.
1394 const double avg = nu * m_tStep * m_nTimeBins;
1395 // Sample the number of pulses.
1396 for (auto& electrode : m_electrodes) {
1397 const int nPulses = RndmPoisson(avg);
1398 for (int j = 0; j < nPulses; ++j) {
1399 const int bin = static_cast<int>(m_nTimeBins * RndmUniform());
1400 electrode.signal[bin] += q0;
1401 }
1402 const double offset = q0 * nu * m_tStep;
1403 for (unsigned int j = 0; j < m_nTimeBins; ++j) {
1404 electrode.signal[j] -= offset;
1405 }
1406 }
1407 } else {
1408 // Gaussian approximation.
1409 const double sigma = enc * sqrt(m_tStep / f2);
1410 for (auto& electrode : m_electrodes) {
1411 for (unsigned int j = 0; j < m_nTimeBins; ++j) {
1412 electrode.signal[j] += RndmGaussian(0., sigma);
1413 }
1414 }
1415 }
1416}
double RndmUniform()
Draw a random number uniformly distributed in the range [0, 1).
Definition: Random.hh:14
double RndmGaussian()
Draw a Gaussian random variate with mean zero and standard deviation one.
Definition: Random.hh:24
int RndmPoisson(const double mean)
Draw a random number from a Poisson distribution.
Definition: Random.cc:664
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314

◆ AddWhiteNoise() [2/2]

void Garfield::Sensor::AddWhiteNoise ( const std::string &  label,
const double  enc,
const bool  poisson = true,
const double  q0 = 1. 
)

Add white noise to the induced signal, given a desired output ENC.

Parameters
labelname of the electrode
encEquivalent Noise Charge, in electrons.
poissonflag to sample the number of noise pulses from a Poisson distribution. Otherwise the noise charge in each bin is sampled from a Gaussian distribution.
q0amplitude of the noise delta pulses (in electrons).

Definition at line 1328 of file Sensor.cc.

1329 {
1330 if (!m_fTransfer && !m_shaper && m_fTransferTab.empty()) {
1331 std::cerr << m_className << "::AddWhiteNoise: Transfer function not set.\n";
1332 return;
1333 }
1334 if (m_nEvents == 0) m_nEvents = 1;
1335
1336 const double f2 = TransferFunctionSq();
1337 if (f2 < 0.) {
1338 std::cerr << m_className << "::AddWhiteNoise:\n"
1339 << " Could not calculate transfer function integral.\n";
1340 return;
1341 }
1342
1343 if (poisson) {
1344 // Frequency of random delta pulses to model noise.
1345 const double nu = (enc * enc / (q0 * q0)) / f2;
1346 // Average number of delta pulses.
1347 const double avg = nu * m_tStep * m_nTimeBins;
1348 // Sample the number of pulses.
1349 for (auto& electrode : m_electrodes) {
1350 if (label != electrode.label) continue;
1351 const int nPulses = RndmPoisson(avg);
1352 for (int j = 0; j < nPulses; ++j) {
1353 const int bin = static_cast<int>(m_nTimeBins * RndmUniform());
1354 electrode.signal[bin] += q0;
1355 }
1356 const double offset = q0 * nu * m_tStep;
1357 for (unsigned int j = 0; j < m_nTimeBins; ++j) {
1358 electrode.signal[j] -= offset;
1359 }
1360 break;
1361 }
1362 } else {
1363 // Gaussian approximation.
1364 const double sigma = enc * sqrt(m_tStep / f2);
1365 for (auto& electrode : m_electrodes) {
1366 if (label != electrode.label) continue;
1367 for (unsigned int j = 0; j < m_nTimeBins; ++j) {
1368 electrode.signal[j] += RndmGaussian(0., sigma);
1369 }
1370 break;
1371 }
1372 }
1373}

◆ Clear()

void Garfield::Sensor::Clear ( )

Remove all components, electrodes and reset the sensor.

Definition at line 379 of file Sensor.cc.

379 {
380 std::lock_guard<std::mutex> guard(m_mutex);
381 m_components.clear();
382 m_lastComponent = nullptr;
383 m_electrodes.clear();
384 m_nTimeBins = 200;
385 m_tStart = 0.;
386 m_tStep = 10.;
387 m_nEvents = 0;
388 m_hasUserArea = false;
389 m_fTransfer = nullptr;
390 m_shaper = nullptr;
391 m_fTransferTab.clear();
392 m_fTransferSq = -1.;
393 m_fTransferFFT.clear();
394}

◆ ClearSignal()

void Garfield::Sensor::ClearSignal ( )

Reset signals and induced charges of all electrodes.

Definition at line 429 of file Sensor.cc.

429 {
430 for (auto& electrode : m_electrodes) {
431 electrode.charge = 0.;
432 electrode.signal.assign(m_nTimeBins, 0.);
433 electrode.delayedSignal.assign(m_nTimeBins, 0.);
434 electrode.electronSignal.assign(m_nTimeBins, 0.);
435 electrode.ionSignal.assign(m_nTimeBins, 0.);
436 electrode.delayedElectronSignal.assign(m_nTimeBins, 0.);
437 electrode.delayedIonSignal.assign(m_nTimeBins, 0.);
438 electrode.integrated = false;
439 }
440 m_nEvents = 0;
441}

Referenced by AddElectrode().

◆ ComputeThresholdCrossings()

bool Garfield::Sensor::ComputeThresholdCrossings ( const double  thr,
const std::string &  label,
int &  n 
)

Determine the threshold crossings of the current signal curve.

Parameters
thrthreshold value
labelelectrode for which to compute the threshold crossings
nnumber of threshold crossings

Definition at line 1439 of file Sensor.cc.

1440 {
1441 // Reset the list of threshold crossings.
1442 m_thresholdCrossings.clear();
1443 m_thresholdLevel = thr;
1444
1445 // Set the interpolation order.
1446 int iOrder = 1;
1447
1448 if (m_nEvents == 0) {
1449 std::cerr << m_className << "::ComputeThresholdCrossings: "
1450 << "No signals present.\n";
1451 return false;
1452 }
1453 // Compute the total signal.
1454 std::vector<double> signal(m_nTimeBins, 0.);
1455 // Loop over the electrodes.
1456 bool foundLabel = false;
1457 for (const auto& electrode : m_electrodes) {
1458 if (electrode.label != label) continue;
1459 foundLabel = true;
1460 if (!electrode.integrated) {
1461 std::cerr << m_className << "::ComputeThresholdCrossings:\n "
1462 << "Warning: signal on electrode " << label
1463 << " has not been integrated/convoluted.\n";
1464 }
1465 for (unsigned int i = 0; i < m_nTimeBins; ++i) {
1466 signal[i] += electrode.signal[i];
1467 }
1468 }
1469 if (!foundLabel) {
1470 std::cerr << m_className << "::ComputeThresholdCrossings: Electrode "
1471 << label << " not found.\n";
1472 return false;
1473 }
1474 const double scale = ElementaryCharge / (m_nEvents * m_tStep);
1475 for (unsigned int i = 0; i < m_nTimeBins; ++i) signal[i] *= scale;
1476
1477 // Establish the range.
1478 const double vMin = *std::min_element(std::begin(signal), std::end(signal));
1479 const double vMax = *std::max_element(std::begin(signal), std::end(signal));
1480 if (m_debug) std::cout << m_className << "::ComputeThresholdCrossings:\n";
1481 if (thr < vMin && thr > vMax) {
1482 if (m_debug) {
1483 std::cout << " Threshold outside the range [" << vMin << ", " << vMax
1484 << "]\n";
1485 }
1486 return true;
1487 }
1488
1489 // Check both rising and falling edges.
1490 constexpr std::array<int, 2> directions = {1, -1};
1491 for (const auto dir : directions) {
1492 const bool up = dir > 0;
1493 if (m_debug) {
1494 if (up) {
1495 std::cout << " Hunting for rising edges.\n";
1496 } else {
1497 std::cout << " Hunting for falling edges.\n";
1498 }
1499 }
1500 // Initialise the vectors.
1501 std::vector<double> ts = {m_tStart + 0.5 * m_tStep};
1502 std::vector<double> vs = {signal[0]};
1503 // Scan the signal.
1504 for (unsigned int i = 1; i < m_nTimeBins; ++i) {
1505 // Compute the vector element.
1506 const double tNew = m_tStart + (i + 0.5) * m_tStep;
1507 const double vNew = signal[i];
1508 // If still increasing or decreasing, add to the vector.
1509 if ((up && vNew > vs.back()) || (!up && vNew < vs.back())) {
1510 ts.push_back(tNew);
1511 vs.push_back(vNew);
1512 continue;
1513 }
1514 // Otherwise see whether we crossed the threshold level.
1515 if ((vs[0] - thr) * (thr - vs.back()) >= 0. && ts.size() > 1 &&
1516 ((up && vs.back() > vs[0]) || (!up && vs.back() < vs[0]))) {
1517 // Compute the crossing time.
1518 double tcr = Numerics::Divdif(ts, vs, ts.size(), thr, iOrder);
1519 m_thresholdCrossings.emplace_back(std::make_pair(tcr, up));
1520 ts = {tNew};
1521 vs = {vNew};
1522 } else {
1523 // No crossing, simply reset the vector.
1524 ts = {tNew};
1525 vs = {vNew};
1526 }
1527 }
1528 // Check the final vector.
1529 if ((vs[0] - thr) * (thr - vs.back()) >= 0. && ts.size() > 1 &&
1530 ((up && vs.back() > vs[0]) || (!up && vs.back() < vs[0]))) {
1531 const double tcr = Numerics::Divdif(ts, vs, ts.size(), thr, iOrder);
1532 m_thresholdCrossings.emplace_back(std::make_pair(tcr, up));
1533 }
1534 }
1535 n = m_thresholdCrossings.size();
1536
1537 if (m_debug) {
1538 std::cout << " Found " << n << " crossings.\n";
1539 if (n > 0) std::cout << " Time [ns] Direction\n";
1540 for (const auto& crossing : m_thresholdCrossings) {
1541 std::cout << " " << crossing.first << " ";
1542 if (crossing.second) {
1543 std::cout << "rising\n";
1544 } else {
1545 std::cout << "falling\n";
1546 }
1547 }
1548 }
1549 // Seems to have worked.
1550 return true;
1551}
double Divdif(const std::vector< double > &f, const std::vector< double > &a, int nn, double x, int mm)
Definition: Numerics.cc:1206

◆ ConvoluteSignal()

bool Garfield::Sensor::ConvoluteSignal ( const std::string &  label,
const bool  fft = false 
)

Convolute the induced current on a given electrode with the transfer function.

Definition at line 1082 of file Sensor.cc.

1082 {
1083 if (!m_fTransfer && !m_shaper && m_fTransferTab.empty()) {
1084 std::cerr << m_className << "::ConvoluteSignal: "
1085 << "Transfer function not set.\n";
1086 return false;
1087 }
1088 if (m_nEvents == 0) {
1089 std::cerr << m_className << "::ConvoluteSignal: No signals present.\n";
1090 return false;
1091 }
1092
1093 if (fft) return ConvoluteSignalFFT(label);
1094 std::vector<double> cnvTab;
1095 MakeTransferFunctionTable(cnvTab);
1096 // Loop over all electrodes.
1097 for (auto& electrode : m_electrodes) {
1098 if (label != electrode.label) continue;
1099 ConvoluteSignal(electrode, cnvTab);
1100 return true;
1101 }
1102 return false;
1103}
bool ConvoluteSignal(const std::string &label, const bool fft=false)
Definition: Sensor.cc:1082

Referenced by ConvoluteSignal(), and ConvoluteSignals().

◆ ConvoluteSignals()

bool Garfield::Sensor::ConvoluteSignals ( const bool  fft = false)

Convolute all induced currents with the transfer function.

Definition at line 1105 of file Sensor.cc.

1105 {
1106 if (!m_fTransfer && !m_shaper && m_fTransferTab.empty()) {
1107 std::cerr << m_className << "::ConvoluteSignals: "
1108 << "Transfer function not set.\n";
1109 return false;
1110 }
1111 if (m_nEvents == 0) {
1112 std::cerr << m_className << "::ConvoluteSignals: No signals present.\n";
1113 return false;
1114 }
1115
1116 if (fft) return ConvoluteSignalFFT();
1117 std::vector<double> cnvTab;
1118 MakeTransferFunctionTable(cnvTab);
1119 // Loop over all electrodes.
1120 for (auto& electrode : m_electrodes) ConvoluteSignal(electrode, cnvTab);
1121 return true;
1122}

◆ DelayAndSubtractFraction()

bool Garfield::Sensor::DelayAndSubtractFraction ( const double  td,
const double  f 
)

Delay the signal and subtract an attenuated copy (modelling a constant fraction discriminator).

\[
  v_{out} = v_{in}\left(t - t_d\right) - f v_{in}.
\]

Definition at line 1283 of file Sensor.cc.

1283 {
1284 const int offset = int(td / m_tStep);
1285 for (auto& electrode : m_electrodes) {
1286 std::vector<double> signal1(m_nTimeBins, 0.);
1287 std::vector<double> signal2(m_nTimeBins, 0.);
1288 for (unsigned int j = 0; j < m_nTimeBins; ++j) {
1289 signal2[j] = f * electrode.signal[j];
1290 const int bin = j - offset;
1291 if (bin < 0 || bin >= (int)m_nTimeBins) continue;
1292 signal1[j] = electrode.signal[bin];
1293 }
1294 for (unsigned int j = 0; j < m_nTimeBins; ++j) {
1295 electrode.signal[j] = signal1[j] - signal2[j];
1296 }
1297 }
1298 return true;
1299}

◆ ElectricField() [1/2]

void Garfield::Sensor::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).

Definition at line 65 of file Sensor.cc.

67 {
68 ex = ey = ez = v = 0.;
69 status = -10;
70 medium = nullptr;
71 double fx = 0., fy = 0., fz = 0., p = 0.;
72 Medium* med = nullptr;
73 int stat = 0;
74 // Add up electric field contributions from all components.
75 for (const auto& cmp : m_components) {
76 if (!std::get<1>(cmp)) continue;
77 std::get<0>(cmp)->ElectricField(x, y, z, fx, fy, fz, p, med, stat);
78 if (status != 0) {
79 status = stat;
80 medium = med;
81 }
82 if (stat == 0) {
83 ex += fx;
84 ey += fy;
85 ez += fz;
86 v += p;
87 }
88 }
89}

Referenced by Heed::HeedFieldMap::field_map(), and Garfield::DriftLineRKF::FieldLine().

◆ ElectricField() [2/2]

void Garfield::Sensor::ElectricField ( const double  x,
const double  y,
const double  z,
double &  ex,
double &  ey,
double &  ez,
Medium *&  medium,
int &  status 
)

Get the drift field at (x, y, z).

Definition at line 91 of file Sensor.cc.

93 {
94 ex = ey = ez = 0.;
95 status = -10;
96 medium = nullptr;
97 double fx = 0., fy = 0., fz = 0.;
98 Medium* med = nullptr;
99 int stat = 0;
100 // Add up electric field contributions from all components.
101 for (const auto& cmp : m_components) {
102 if (!std::get<1>(cmp)) continue;
103 std::get<0>(cmp)->ElectricField(x, y, z, fx, fy, fz, med, stat);
104 if (status != 0) {
105 status = stat;
106 medium = med;
107 }
108 if (stat == 0) {
109 ex += fx;
110 ey += fy;
111 ez += fz;
112 }
113 }
114}

◆ EnableComponent()

void Garfield::Sensor::EnableComponent ( const unsigned int  i,
const bool  on 
)

Activate/deactivate a given component.

Definition at line 333 of file Sensor.cc.

333 {
334 if (i >= m_components.size()) {
335 std::cerr << m_className << "::EnableComponent: Index out of range.\n";
336 return;
337 };
338 std::get<1>(m_components[i]) = on;
339}

◆ EnableDebugging()

void Garfield::Sensor::EnableDebugging ( const bool  on = true)
inline

Switch debugging messages on/off.

Definition at line 67 of file Sensor.hh.

67{ m_debug = on; }

◆ EnableDelayedSignal()

void Garfield::Sensor::EnableDelayedSignal ( const bool  on = true)
inline

Compute the component of the signal due to the delayed weighting field.

Definition at line 104 of file Sensor.hh.

104{ m_delayedSignal = on; }

◆ EnableMagneticField()

void Garfield::Sensor::EnableMagneticField ( const unsigned int  i,
const bool  on 
)

Activate/deactivate use of the magnetic field of a given component.

Definition at line 341 of file Sensor.cc.

341 {
342 if (i >= m_components.size()) {
343 std::cerr << m_className << "::EnableMagneticField: Index out of range.\n";
344 return;
345 };
346 std::get<2>(m_components[i]) = on;
347}

◆ EnableTransferFunctionCache()

void Garfield::Sensor::EnableTransferFunctionCache ( const bool  on = true)
inline

Cache integral and FFT of the transfer function instead of recomputing it at every call (default: on).

Definition at line 152 of file Sensor.hh.

152 {
153 m_cacheTransferFunction = on;
154 }

◆ ExportSignal()

void Garfield::Sensor::ExportSignal ( const std::string &  label,
const std::string &  filename 
)

Exporting induced signal to a csv file.

Definition at line 1663 of file Sensor.cc.

1664 {
1665
1666 const double scale = m_nEvents > 0 ? ElementaryCharge / (m_nEvents * m_tStep) : 0.;
1667 for (const auto& electrode : m_electrodes) {
1668 if (electrode.label != label) continue;
1669 std::ofstream myfile;
1670 std::string filename = name + ".csv";
1671 myfile.open(filename);
1672 if (myfile.fail()) {
1673 std::cerr << m_className << "::ExportSignal:\n"
1674 << " Could not open file " << filename << ".\n";
1675 return;
1676 }
1677 if (electrode.integrated) {
1678 myfile << "The cumulative induced charge.\n";
1679 myfile << "Time [ns],Prompt [fC],Delayed [fC],Total [fC],\n";
1680 } else {
1681 myfile << "The induced signal.\n";
1682 myfile << "Time [ns],Prompt [fC/ns],Delayed [fC/ns],Total [fC/ns];\n";
1683 }
1684 for (unsigned int i = 0; i < m_nTimeBins; i++) {
1685 myfile << std::setprecision(std::numeric_limits<long double>::digits10 +
1686 1)
1687 << m_tStart + i * m_tStep << ","
1688 << scale * (electrode.signal[i] - electrode.delayedSignal[i])
1689 << ","
1690 << scale * electrode.delayedSignal[i] << ","
1691 << scale * electrode.signal[i] << "\n";
1692 }
1693 myfile.close();
1694 std::cerr << m_className << "::ExportSignal: File '" << filename
1695 << ".csv' exported.\n";
1696 break;
1697 }
1698}

◆ GetArea()

bool Garfield::Sensor::GetArea ( double &  xmin,
double &  ymin,
double &  zmin,
double &  xmax,
double &  ymax,
double &  zmax 
)

Return the current user area.

Definition at line 228 of file Sensor.cc.

229 {
230 if (m_hasUserArea) {
231 xmin = m_xMinUser;
232 ymin = m_yMinUser;
233 zmin = m_zMinUser;
234 xmax = m_xMaxUser;
235 ymax = m_yMaxUser;
236 zmax = m_zMaxUser;
237 return true;
238 }
239
240 // User area bounds are not (yet) defined.
241 // Get the bounding box of the sensor.
242 if (!SetArea()) return false;
243
244 xmin = m_xMinUser;
245 ymin = m_yMinUser;
246 zmin = m_zMinUser;
247 xmax = m_xMaxUser;
248 ymax = m_yMaxUser;
249 zmax = m_zMaxUser;
250
251 return true;
252}
bool SetArea()
Set the user area to the default.
Definition: Sensor.cc:183

Referenced by Garfield::DriftLineRKF::FieldLine(), Garfield::TrackSrim::NewTrack(), and Garfield::ViewBase::PlotLimits().

◆ GetComponent()

Component * Garfield::Sensor::GetComponent ( const unsigned int  i)

Retrieve the pointer to a given component.

Definition at line 325 of file Sensor.cc.

325 {
326 if (i >= m_components.size()) {
327 std::cerr << m_className << "::GetComponent: Index out of range.\n";
328 return nullptr;
329 };
330 return std::get<0>(m_components[i]);
331}

◆ GetDelayedElectronSignal()

double Garfield::Sensor::GetDelayedElectronSignal ( const std::string &  label,
const unsigned int  bin 
)

Retrieve the delayed electron signal for a given electrode and time bin.

Definition at line 878 of file Sensor.cc.

879 {
880 if (m_nEvents == 0) return 0.;
881 if (bin >= m_nTimeBins) return 0.;
882 double sig = 0.;
883 for (const auto& electrode : m_electrodes) {
884 if (electrode.label == label) sig += electrode.delayedElectronSignal[bin];
885 }
886 return ElementaryCharge * sig / (m_nEvents * m_tStep);
887}

Referenced by Garfield::ViewSignal::PlotSignal().

◆ GetDelayedIonSignal()

double Garfield::Sensor::GetDelayedIonSignal ( const std::string &  label,
const unsigned int  bin 
)

Retrieve the delayed ion/hole signal for a given electrode and time bin.

Definition at line 889 of file Sensor.cc.

890 {
891 if (m_nEvents == 0) return 0.;
892 if (bin >= m_nTimeBins) return 0.;
893 double sig = 0.;
894 for (const auto& electrode : m_electrodes) {
895 if (electrode.label == label) sig += electrode.delayedIonSignal[bin];
896 }
897 return ElementaryCharge * sig / (m_nEvents * m_tStep);
898}

Referenced by Garfield::ViewSignal::PlotSignal().

◆ GetDelayedSignal()

double Garfield::Sensor::GetDelayedSignal ( const std::string &  label,
const unsigned int  bin 
)

Retrieve the delayed signal for a given electrode and time bin.

Definition at line 958 of file Sensor.cc.

959 {
960 if (m_nEvents == 0) return 0.;
961 if (bin >= m_nTimeBins) return 0.;
962 double sig = 0.;
963 for (const auto& electrode : m_electrodes) {
964 if (electrode.label == label) sig += electrode.delayedSignal[bin];
965 }
966 return ElementaryCharge * sig / (m_nEvents * m_tStep);
967}

◆ GetElectronSignal()

double Garfield::Sensor::GetElectronSignal ( const std::string &  label,
const unsigned int  bin 
)

Retrieve the electron signal for a given electrode and time bin.

Definition at line 857 of file Sensor.cc.

858 {
859 if (m_nEvents == 0) return 0.;
860 if (bin >= m_nTimeBins) return 0.;
861 double sig = 0.;
862 for (const auto& electrode : m_electrodes) {
863 if (electrode.label == label) sig += electrode.electronSignal[bin];
864 }
865 return ElementaryCharge * sig / (m_nEvents * m_tStep);
866}

Referenced by main(), and Garfield::ViewSignal::PlotSignal().

◆ GetInducedCharge()

double Garfield::Sensor::GetInducedCharge ( const std::string &  label)

Calculated using the weighting potentials at the start and end points.

Definition at line 969 of file Sensor.cc.

969 {
970 if (m_nEvents == 0) return 0.;
971 double charge = 0.;
972 for (const auto& electrode : m_electrodes) {
973 if (electrode.label == label) charge += electrode.charge;
974 }
975
976 return charge / m_nEvents;
977}

◆ GetIonSignal()

double Garfield::Sensor::GetIonSignal ( const std::string &  label,
const unsigned int  bin 
)

Retrieve the ion or hole signal for a given electrode and time bin.

Definition at line 868 of file Sensor.cc.

868 {
869 if (m_nEvents == 0) return 0.;
870 if (bin >= m_nTimeBins) return 0.;
871 double sig = 0.;
872 for (const auto& electrode : m_electrodes) {
873 if (electrode.label == label) sig += electrode.ionSignal[bin];
874 }
875 return ElementaryCharge * sig / (m_nEvents * m_tStep);
876}

Referenced by main(), and Garfield::ViewSignal::PlotSignal().

◆ GetMedium()

bool Garfield::Sensor::GetMedium ( const double  x,
const double  y,
const double  z,
Medium *&  medium 
)

Get the medium at (x, y, z).

Definition at line 159 of file Sensor.cc.

160 {
161 m = nullptr;
162
163 // Make sure there is at least one component.
164 if (m_components.empty()) return false;
165
166 // Check if we are still in the same component as in the previous call.
167 if (m_lastComponent) {
168 m = m_lastComponent->GetMedium(x, y, z);
169 if (m) return true;
170 }
171
172 for (const auto& cmp : m_components) {
173 if (!std::get<1>(cmp)) continue;
174 m = std::get<0>(cmp)->GetMedium(x, y, z);
175 if (m) {
176 m_lastComponent = std::get<0>(cmp);
177 return true;
178 }
179 }
180 return false;
181}
virtual Medium * GetMedium(const double x, const double y, const double z)
Get the medium at a given location (x, y, z).
Definition: Component.cc:22

Referenced by Garfield::TrackBichsel::GetCluster(), Garfield::TrackSimple::GetCluster(), Garfield::TrackElectron::GetCluster(), Garfield::TrackPAI::GetCluster(), Heed::HeedFieldMap::inside(), Garfield::TrackBichsel::NewTrack(), Garfield::TrackElectron::NewTrack(), Garfield::TrackPAI::NewTrack(), Garfield::TrackSimple::NewTrack(), Garfield::TrackHeed::NewTrack(), Garfield::TrackSrim::NewTrack(), Garfield::TrackTrim::NewTrack(), Garfield::TrackHeed::TransportDeltaElectron(), and Garfield::TrackHeed::TransportPhoton().

◆ GetNumberOfComponents()

size_t Garfield::Sensor::GetNumberOfComponents ( ) const
inline

Get the number of components attached to the sensor.

Definition at line 27 of file Sensor.hh.

27{ return m_components.size(); }

◆ GetNumberOfElectrodes()

size_t Garfield::Sensor::GetNumberOfElectrodes ( ) const
inline

Get the number of electrodes attached to the sensor.

Definition at line 38 of file Sensor.hh.

38{ return m_electrodes.size(); }

◆ GetNumberOfThresholdCrossings()

size_t Garfield::Sensor::GetNumberOfThresholdCrossings ( ) const
inline

Get the number of threshold crossings (after having called ComputeThresholdCrossings).

Definition at line 201 of file Sensor.hh.

201 {
202 return m_thresholdCrossings.size();
203 }

Referenced by Garfield::ViewSignal::Plot(), and Garfield::ViewSignal::PlotSignal().

◆ GetPromptSignal()

double Garfield::Sensor::GetPromptSignal ( const std::string &  label,
const unsigned int  bin 
)

Retrieve the prompt signal for a given electrode and time bin.

Definition at line 946 of file Sensor.cc.

947 {
948 if (m_nEvents == 0) return 0.;
949 if (bin >= m_nTimeBins) return 0.;
950 double sig = 0.;
951 for (const auto& electrode : m_electrodes) {
952 if (electrode.label == label)
953 sig += electrode.signal[bin] - electrode.delayedSignal[bin];
954 }
955 return ElementaryCharge * sig / (m_nEvents * m_tStep);
956}

◆ GetSignal() [1/2]

double Garfield::Sensor::GetSignal ( const std::string &  label,
const unsigned int  bin 
)

Retrieve the total signal for a given electrode and time bin.

Definition at line 912 of file Sensor.cc.

912 {
913 if (m_nEvents == 0) return 0.;
914 if (bin >= m_nTimeBins) return 0.;
915 double sig = 0.;
916 for (const auto& electrode : m_electrodes) {
917 if (electrode.label == label) sig += electrode.signal[bin];
918 }
919 return ElementaryCharge * sig / (m_nEvents * m_tStep);
920}

Referenced by main(), Garfield::ViewSignal::Plot(), and Garfield::ViewSignal::PlotSignal().

◆ GetSignal() [2/2]

double Garfield::Sensor::GetSignal ( const std::string &  label,
const unsigned int  bin,
const int  comp 
)

Retrieve the electron signal for a given electrode and time bin.

Definition at line 922 of file Sensor.cc.

923 {
924 if (m_nEvents == 0) return 0.;
925 if (bin >= m_nTimeBins) return 0.;
926 double sig = 0.;
927 for (const auto& electrode : m_electrodes) {
928 if (electrode.label == label) {
929 switch (comp) {
930 case 1: {
931 sig += electrode.signal[bin] - electrode.delayedSignal[bin];
932 break;
933 }
934 case 2: {
935 sig += electrode.delayedSignal[bin];
936 break;
937 }
938 default:
939 sig += electrode.signal[bin];
940 }
941 }
942 }
943 return ElementaryCharge * sig / (m_nEvents * m_tStep);
944}

◆ GetThresholdCrossing()

bool Garfield::Sensor::GetThresholdCrossing ( const unsigned int  i,
double &  time,
double &  level,
bool &  rise 
) const

Retrieve the time and type of a given threshold crossing (after having called ComputeThresholdCrossings.

Parameters
iindex
timethreshold crossing time [ns]
levelthreshold (should correspond to the value requested).
riseflag whether the crossing is on a rising or falling slope.

Definition at line 1553 of file Sensor.cc.

1554 {
1555 level = m_thresholdLevel;
1556
1557 if (i >= m_thresholdCrossings.size()) {
1558 std::cerr << m_className << "::GetThresholdCrossing: Index out of range.\n";
1559 time = m_tStart + m_nTimeBins * m_tStep;
1560 return false;
1561 }
1562
1563 time = m_thresholdCrossings[i].first;
1564 rise = m_thresholdCrossings[i].second;
1565 return true;
1566}

Referenced by Garfield::ViewSignal::Plot(), and Garfield::ViewSignal::PlotSignal().

◆ GetTimeWindow()

void Garfield::Sensor::GetTimeWindow ( double &  tstart,
double &  tstep,
unsigned int &  nsteps 
) const
inline

Retrieve the time window and binning.

Definition at line 96 of file Sensor.hh.

97 {
98 tstart = m_tStart;
99 tstep = m_tStep;
100 nsteps = m_nTimeBins;
101 }

Referenced by Garfield::ViewSignal::Plot(), and Garfield::ViewSignal::PlotSignal().

◆ GetTotalInducedCharge()

double Garfield::Sensor::GetTotalInducedCharge ( const std::string  label)

Definition at line 1700 of file Sensor.cc.

1700 {
1701 for (const auto& electrode : m_electrodes) {
1702 if (electrode.label != label) continue;
1703 if (!electrode.integrated || m_nEvents == 0) return 0.;
1704 return ElementaryCharge * electrode.signal.back() / (m_nEvents * m_tStep);
1705 }
1706 return 0.;
1707}

◆ GetTransferFunction()

double Garfield::Sensor::GetTransferFunction ( const double  t)

Evaluate the transfer function at a given time.

Definition at line 1041 of file Sensor.cc.

1041 {
1042 if (m_fTransfer) {
1043 return m_fTransfer(t);
1044 } else if (m_shaper) {
1045 return m_shaper->Shape(t);
1046 }
1047 return InterpolateTransferFunctionTable(t);
1048}
double Shape(const double t) const
Evaluate the transfer function.
Definition: Shaper.cc:50

Referenced by PrintTransferFunction().

◆ GetVoltageRange()

bool Garfield::Sensor::GetVoltageRange ( double &  vmin,
double &  vmax 
)

Return the voltage range.

Definition at line 396 of file Sensor.cc.

396 {
397 // We don't know the range yet.
398 bool set = false;
399 // Loop over the components.
400 for (const auto& cmp : m_components) {
401 if (!std::get<1>(cmp)) continue;
402 double umin = 0., umax = 0.;
403 if (!std::get<0>(cmp)->GetVoltageRange(umin, umax)) continue;
404 if (set) {
405 vmin = std::min(umin, vmin);
406 vmax = std::max(umax, vmax);
407 } else {
408 vmin = umin;
409 vmax = umax;
410 set = true;
411 }
412 }
413
414 // Warn if we still don't know the range.
415 if (!set) {
416 std::cerr << m_className << "::GetVoltageRange:\n"
417 << " Sensor voltage range not known.\n";
418 vmin = vmax = 0.;
419 return false;
420 }
421
422 if (m_debug) {
423 std::cout << m_className << "::GetVoltageRange: " << vmin << " < V < "
424 << vmax << ".\n";
425 }
426 return true;
427}
bool GetVoltageRange(double &vmin, double &vmax)
Return the voltage range.
Definition: Sensor.cc:396

Referenced by GetVoltageRange().

◆ IntegrateFluxLine()

double Garfield::Sensor::IntegrateFluxLine ( const double  x0,
const double  y0,
const double  z0,
const double  x1,
const double  y1,
const double  z1,
const double  xp,
const double  yp,
const double  zp,
const unsigned int  nI,
const int  isign = 0 
)

Integrate the electric field flux through a line from (x0,y0,z0) to (x1,y1,z1) along a direction (xp,yp,zp).

Definition at line 301 of file Sensor.cc.

306 {
307 double q = 0.;
308 for (const auto& cmp : m_components) {
309 if (!std::get<1>(cmp)) continue;
310 q += std::get<0>(cmp)->IntegrateFluxLine(x0, y0, z0, x1, y1, z1, xp, yp, zp,
311 nI, isign);
312 }
313 return q;
314}

Referenced by Garfield::ViewField::EqualFluxIntervals(), and Garfield::ViewField::FixedFluxIntervals().

◆ IntegrateSignal()

bool Garfield::Sensor::IntegrateSignal ( const std::string &  label)

Replace the signal on a given electrode by its integral.

Definition at line 1244 of file Sensor.cc.

1244 {
1245 if (m_nEvents == 0) {
1246 std::cerr << m_className << "::IntegrateSignal: No signals present.\n";
1247 return false;
1248 }
1249
1250 for (auto& electrode : m_electrodes) {
1251 if (label != electrode.label) continue;
1252 IntegrateSignal(electrode);
1253 return true;
1254 }
1255 std::cerr << m_className << "::IntegrateSignal: Electrode " << label
1256 << " not found.\n";
1257 return false;
1258}
bool IntegrateSignal(const std::string &label)
Replace the signal on a given electrode by its integral.
Definition: Sensor.cc:1244

Referenced by IntegrateSignal(), IntegrateSignals(), and Garfield::ViewSignal::Plot().

◆ IntegrateSignals()

bool Garfield::Sensor::IntegrateSignals ( )

Replace the signals on all electrodes curve by their integrals.

Definition at line 1234 of file Sensor.cc.

1234 {
1235 if (m_nEvents == 0) {
1236 std::cerr << m_className << "::IntegrateSignals: No signals present.\n";
1237 return false;
1238 }
1239
1240 for (auto& electrode : m_electrodes) IntegrateSignal(electrode);
1241 return true;
1242}

Referenced by main().

◆ IsInArea()

bool Garfield::Sensor::IsInArea ( const double  x,
const double  y,
const double  z 
)

Check if a point is inside the user area.

Definition at line 254 of file Sensor.cc.

254 {
255 if (!m_hasUserArea) {
256 if (!SetArea()) {
257 std::cerr << m_className << "::IsInArea: User area could not be set.\n";
258 return false;
259 }
260 m_hasUserArea = true;
261 }
262
263 if (x >= m_xMinUser && x <= m_xMaxUser && y >= m_yMinUser &&
264 y <= m_yMaxUser && z >= m_zMinUser && z <= m_zMaxUser) {
265 return true;
266 }
267
268 if (m_debug) {
269 std::cout << m_className << "::IsInArea: (" << x << ", " << y << ", " << z
270 << ") "
271 << " is outside.\n";
272 }
273 return false;
274}

Referenced by Garfield::TrackElectron::GetCluster(), Garfield::TrackPAI::GetCluster(), Heed::HeedFieldMap::inside(), and Garfield::TrackSrim::NewTrack().

◆ IsIntegrated()

bool Garfield::Sensor::IsIntegrated ( const std::string &  label) const

Return whether the signal has been integrated/convoluted.

Definition at line 1276 of file Sensor.cc.

1276 {
1277 for (const auto& electrode : m_electrodes) {
1278 if (electrode.label == label) return electrode.integrated;
1279 }
1280 return false;
1281}

Referenced by Garfield::ViewSignal::PlotSignal().

◆ IsInTrapRadius()

bool Garfield::Sensor::IsInTrapRadius ( const double  q0,
const double  x0,
const double  y0,
const double  z0,
double &  xw,
double &  yw,
double &  rw 
)

Definition at line 290 of file Sensor.cc.

291 {
292 for (const auto& cmp : m_components) {
293 if (!std::get<1>(cmp)) continue;
294 if (std::get<0>(cmp)->IsInTrapRadius(q0, x0, y0, z0, xw, yw, rw)) {
295 return true;
296 }
297 }
298 return false;
299}
bool IsInTrapRadius(const double q0, const double x0, const double y0, const double z0, double &xw, double &yw, double &rw)
Definition: Sensor.cc:290

Referenced by IsInTrapRadius().

◆ IsWireCrossed()

bool Garfield::Sensor::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,
const bool  centre,
double &  rc 
)

Determine whether a line between two points has crossed a wire, calls Component::IsWireCrossed.

Definition at line 276 of file Sensor.cc.

279 {
280 for (const auto& cmp : m_components) {
281 if (!std::get<1>(cmp)) continue;
282 if (std::get<0>(cmp)->IsWireCrossed(x0, y0, z0, x1, y1, z1, xc, yc, zc,
283 centre, rc)) {
284 return true;
285 }
286 }
287 return false;
288}
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, const bool centre, double &rc)
Definition: Sensor.cc:276

Referenced by Garfield::DriftLineRKF::FieldLine(), and IsWireCrossed().

◆ MagneticField()

void Garfield::Sensor::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).

Definition at line 116 of file Sensor.cc.

117 {
118 bx = by = bz = 0.;
119 double fx = 0., fy = 0., fz = 0.;
120 // Add up contributions.
121 for (const auto& cmp : m_components) {
122 if (!std::get<2>(cmp)) continue;
123 std::get<0>(cmp)->MagneticField(x, y, z, fx, fy, fz, status);
124 if (status != 0) continue;
125 bx += fx;
126 by += fy;
127 bz += fz;
128 }
129}

Referenced by Heed::HeedFieldMap::field_map().

◆ NewSignal()

void Garfield::Sensor::NewSignal ( )
inline

Start a new event, when computing the average signal over multiple events.

Definition at line 84 of file Sensor.hh.

84{ ++m_nEvents; }

◆ PrintTransferFunction()

void Garfield::Sensor::PrintTransferFunction ( )

Print some information about the presently set transfer function.

Definition at line 1050 of file Sensor.cc.

1050 {
1051
1052 std::cout << m_className << "::PrintTransferFunction:\n";
1053 if (m_fTransfer) {
1054 std::cout << " User-defined function.";
1055 } else if (m_shaper) {
1056 std::string shaperType = "Unknown";
1057 if (m_shaper->IsUnipolar()) {
1058 shaperType = "Unipolar";
1059 } else if (m_shaper->IsBipolar()) {
1060 shaperType = "Bipolar";
1061 }
1062 unsigned int n = 1;
1063 double tp = 0.;
1064 m_shaper->GetParameters(n, tp);
1065 std::printf(" %s shaper with order %u and %5.1f ns peaking time.\n",
1066 shaperType.c_str(), n, tp);
1067 } else if (!m_fTransferTab.empty()) {
1068 std::cout << " Table with " << m_fTransferTab.size() << " entries.\n";
1069 } else {
1070 std::cout << " No transfer function set.\n";
1071 return;
1072 }
1073 std::cout << " Time [ns] Transfer function\n";
1074 const double dt = m_nTimeBins * m_tStep / 10.;
1075 for (size_t i = 0; i < 10; ++i) {
1076 const double t = m_tStart + (i + 0.5) * dt;
1077 const double f = GetTransferFunction(t);
1078 std::printf(" %10.3f %10.5f\n", t, f);
1079 }
1080}
double GetTransferFunction(const double t)
Evaluate the transfer function at a given time.
Definition: Sensor.cc:1041
bool IsUnipolar() const
Is it a unipolar shaper?
Definition: Shaper.hh:34
void GetParameters(unsigned int &n, double &tp)
Retrieve the parameters.
Definition: Shaper.hh:38
bool IsBipolar() const
Is it a bipolar shaper?
Definition: Shaper.hh:36

◆ SetArea() [1/2]

bool Garfield::Sensor::SetArea ( )

Set the user area to the default.

Definition at line 183 of file Sensor.cc.

183 {
184 std::lock_guard<std::mutex> guard(m_mutex);
185 if (!GetBoundingBox(m_xMinUser, m_yMinUser, m_zMinUser, m_xMaxUser,
186 m_yMaxUser, m_zMaxUser)) {
187 std::cerr << m_className << "::SetArea: Bounding box is not known.\n";
188 return false;
189 }
190
191 std::cout << m_className << "::SetArea:\n"
192 << " " << m_xMinUser << " < x [cm] < " << m_xMaxUser << "\n"
193 << " " << m_yMinUser << " < y [cm] < " << m_yMaxUser << "\n"
194 << " " << m_zMinUser << " < z [cm] < " << m_zMaxUser << "\n";
195 if (std::isinf(m_xMinUser) || std::isinf(m_xMaxUser)) {
196 std::cerr << m_className << "::SetArea: Warning. Infinite x-range.\n";
197 }
198 if (std::isinf(m_yMinUser) || std::isinf(m_yMaxUser)) {
199 std::cerr << m_className << "::SetArea: Warning. Infinite y-range.\n";
200 }
201 if (std::isinf(m_zMinUser) || std::isinf(m_zMaxUser)) {
202 std::cerr << m_className << "::SetArea: Warning. Infinite z-range.\n";
203 }
204 m_hasUserArea = true;
205 return true;
206}

Referenced by GetArea(), IsInArea(), main(), and Garfield::ViewField::PlotFieldLines().

◆ SetArea() [2/2]

bool Garfield::Sensor::SetArea ( const double  xmin,
const double  ymin,
const double  zmin,
const double  xmax,
const double  ymax,
const double  zmax 
)

Set the user area explicitly.

Definition at line 208 of file Sensor.cc.

209 {
210 std::lock_guard<std::mutex> guard(m_mutex);
211 if (fabs(xmax - xmin) < Small || fabs(ymax - ymin) < Small ||
212 fabs(zmax - zmin) < Small) {
213 std::cerr << m_className << "::SetArea: Invalid range.\n";
214 return false;
215 }
216
217 m_xMinUser = std::min(xmin, xmax);
218 m_yMinUser = std::min(ymin, ymax);
219 m_zMinUser = std::min(zmin, zmax);
220 m_xMaxUser = std::max(xmax, xmin);
221 m_yMaxUser = std::max(ymax, ymin);
222 m_zMaxUser = std::max(zmax, zmin);
223
224 m_hasUserArea = true;
225 return true;
226}
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:615

◆ SetDelayedSignalAveragingOrder()

void Garfield::Sensor::SetDelayedSignalAveragingOrder ( const unsigned int  navg)
inline

Set the number of points to be used when averaging the delayed signal vector over a time bin (default: 0). The averaging is done with a $2\times navg + 1$ point Newton-Raphson integration.

Definition at line 111 of file Sensor.hh.

111 {
112 m_nAvgDelayedSignal = navg;
113 }

◆ SetDelayedSignalTimes()

void Garfield::Sensor::SetDelayedSignalTimes ( const std::vector< double > &  ts)

Set the points in time at which to evaluate the delayed weighting field.

Definition at line 443 of file Sensor.cc.

443 {
444 if (!std::is_sorted(ts.begin(), ts.end())) {
445 std::cerr << m_className << "::SetDelayedSignalTimes:\n"
446 << " Times are not in ascending order.\n";
447 return;
448 }
449 m_delayedSignalTimes = ts;
450}

◆ SetNoiseFunction()

void Garfield::Sensor::SetNoiseFunction ( double(*)(double t)  f)

Set the function to be used for evaluating the noise component.

Definition at line 1301 of file Sensor.cc.

1301 {
1302 if (!f) {
1303 std::cerr << m_className << "::SetNoiseFunction: Null pointer.\n";
1304 return;
1305 }
1306 m_fNoise = f;
1307}

◆ SetSignal()

void Garfield::Sensor::SetSignal ( const std::string &  label,
const unsigned int  bin,
const double  signal 
)

Set/override the signal in a given time bin explicitly.

Definition at line 900 of file Sensor.cc.

901 {
902 if (bin >= m_nTimeBins) return;
903 if (m_nEvents == 0) m_nEvents = 1;
904 for (auto& electrode : m_electrodes) {
905 if (electrode.label == label) {
906 electrode.signal[bin] = m_nEvents * m_tStep * signal / ElementaryCharge;
907 break;
908 }
909 }
910}

◆ SetTimeWindow()

void Garfield::Sensor::SetTimeWindow ( const double  tstart,
const double  tstep,
const unsigned int  nsteps 
)

Set the time window and binning for the signal calculation.

Parameters
tstartstart time [ns]
tstepbin width [ns]
nstepsnumber of bins

Definition at line 820 of file Sensor.cc.

821 {
822 m_tStart = tstart;
823 if (tstep <= 0.) {
824 std::cerr << m_className << "::SetTimeWindow: Start time out of range.\n";
825 } else {
826 m_tStep = tstep;
827 }
828
829 if (nsteps == 0) {
830 std::cerr << m_className << "::SetTimeWindow: Invalid number of bins.\n";
831 } else {
832 m_nTimeBins = nsteps;
833 }
834
835 if (m_debug) {
836 std::cout << m_className << "::SetTimeWindow: " << m_tStart
837 << " < t [ns] < " << m_tStart + m_nTimeBins * m_tStep << "\n"
838 << " Step size: " << m_tStep << " ns\n";
839 }
840
841 std::cout << m_className << "::SetTimeWindow: Resetting all signals.\n";
842 for (auto& electrode : m_electrodes) {
843 electrode.signal.assign(m_nTimeBins, 0.);
844 electrode.electronSignal.assign(m_nTimeBins, 0.);
845 electrode.ionSignal.assign(m_nTimeBins, 0.);
846 electrode.delayedSignal.assign(m_nTimeBins, 0.);
847 electrode.delayedElectronSignal.assign(m_nTimeBins, 0.);
848 electrode.delayedIonSignal.assign(m_nTimeBins, 0.);
849 electrode.integrated = false;
850 }
851 m_nEvents = 0;
852 // Reset the cached FFT of the transfer function
853 // because it depends on the number of time bins.
854 m_fTransferFFT.clear();
855}

Referenced by main().

◆ SetTransferFunction() [1/3]

void Garfield::Sensor::SetTransferFunction ( const std::vector< double > &  times,
const std::vector< double > &  values 
)

Set the points to be used for interpolating the transfer function.

Definition at line 991 of file Sensor.cc.

992 {
993 if (times.empty() || values.empty()) {
994 std::cerr << m_className << "::SetTransferFunction: Empty vector.\n";
995 return;
996 } else if (times.size() != values.size()) {
997 std::cerr << m_className << "::SetTransferFunction:\n"
998 << " Time and value vectors must have same size.\n";
999 return;
1000 }
1001 const auto n = times.size();
1002 m_fTransferTab.clear();
1003 for (unsigned int i = 0; i < n; ++i) {
1004 m_fTransferTab.emplace_back(std::make_pair(times[i], values[i]));
1005 }
1006 std::sort(m_fTransferTab.begin(), m_fTransferTab.end());
1007 m_fTransfer = nullptr;
1008 m_shaper = nullptr;
1009 m_fTransferSq = -1.;
1010 m_fTransferFFT.clear();
1011}

◆ SetTransferFunction() [2/3]

void Garfield::Sensor::SetTransferFunction ( double(*)(double t)  f)

Set the function to be used for evaluating the transfer function.

Definition at line 979 of file Sensor.cc.

979 {
980 if (!f) {
981 std::cerr << m_className << "::SetTransferFunction: Null pointer.\n";
982 return;
983 }
984 m_fTransfer = f;
985 m_shaper = nullptr;
986 m_fTransferTab.clear();
987 m_fTransferSq = -1.;
988 m_fTransferFFT.clear();
989}

◆ SetTransferFunction() [3/3]

void Garfield::Sensor::SetTransferFunction ( Shaper shaper)

Set the transfer function using a Shaper object.

Definition at line 1013 of file Sensor.cc.

1013 {
1014 m_shaper = &shaper;
1015 m_fTransfer = nullptr;
1016 m_fTransferTab.clear();
1017 m_fTransferSq = -1.;
1018 m_fTransferFFT.clear();
1019}

◆ WeightingField()

void Garfield::Sensor::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).

Definition at line 131 of file Sensor.cc.

133 {
134 wx = wy = wz = 0.;
135 // Add up field contributions from all components.
136 for (const auto& electrode : m_electrodes) {
137 if (electrode.label == label) {
138 double fx = 0., fy = 0., fz = 0.;
139 electrode.comp->WeightingField(x, y, z, fx, fy, fz, label);
140 wx += fx;
141 wy += fy;
142 wz += fz;
143 }
144 }
145}

◆ WeightingPotential()

double Garfield::Sensor::WeightingPotential ( const double  x,
const double  y,
const double  z,
const std::string &  label 
)

Get the weighting potential at (x, y, z).

Definition at line 147 of file Sensor.cc.

148 {
149 double v = 0.;
150 // Add up contributions from all components.
151 for (const auto& electrode : m_electrodes) {
152 if (electrode.label == label) {
153 v += electrode.comp->WeightingPotential(x, y, z, label);
154 }
155 }
156 return v;
157}

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