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::DriftLineRKF Class Reference

#include <DriftLineRKF.hh>

Public Member Functions

 DriftLineRKF ()
 Constructor.
 
 ~DriftLineRKF ()
 Destructor.
 
void SetSensor (Sensor *s)
 Set the sensor.
 
void EnablePlotting (ViewDrift *view)
 Switch on drift line plotting.
 
void DisablePlotting ()
 Switch off drift line plotting.
 
void EnableSignalCalculation (const bool on=true)
 Switch on/off calculation of induced currents (default: enabled).
 
void SetSignalAveragingOrder (const unsigned int navg)
 
void SetIntegrationAccuracy (const double eps)
 Set the accuracy of the Runge Kutta Fehlberg drift line integration.
 
void SetMaximumStepSize (const double ms)
 Set the maximum step size that is allowed. By default, there is no limit.
 
void UnsetMaximumStepSize ()
 Do not apply an upper limit to the step size that is allowed.
 
void RejectKinks (const bool on=true)
 
void SetElectronSignalScalingFactor (const double scale)
 Set multiplication factor for the signal induced by electrons.
 
void SetHoleSignalScalingFactor (const double scale)
 Set multiplication factor for the signal induced by holes.
 
void SetIonSignalScalingFactor (const double scale)
 Set multiplication factor for the signal induced by ions.
 
void EnableAvalanche (const bool on=true)
 Enable/disable simulation electron multiplication (default: on).
 
void EnableIonTail (const bool on=true)
 Enable/disable simulation of the ion tail (default: off).
 
void SetGainFluctuationsFixed (const double gain=-1.)
 Do not randomize the avalanche size.
 
void SetGainFluctuationsPolya (const double theta, const double mean=-1.)
 
bool DriftElectron (const double x0, const double y0, const double z0, const double t0)
 Simulate the drift line of an electron with a given starting point.
 
bool DriftHole (const double x0, const double y0, const double z0, const double t0)
 Simulate the drift line of a hole with a given starting point.
 
bool DriftIon (const double x0, const double y0, const double z0, const double t0)
 Simulate the drift line of an ion with a given starting point.
 
bool DriftPositron (const double x0, const double y0, const double z0, const double t0)
 
bool DriftNegativeIon (const double x0, const double y0, const double z0, const double t0)
 
void PrintDriftLine () const
 Print the trajectory of the most recent drift line.
 
void GetEndPoint (double &x, double &y, double &z, double &t, int &st) const
 Get the end point and status flag of the most recent drift line.
 
unsigned int GetNumberOfDriftLinePoints () const
 Get the number of points of the most recent drift line.
 
void GetDriftLinePoint (const unsigned int i, double &x, double &y, double &z, double &t) const
 Get the coordinates and time of a point along the most recent drift line.
 
double GetArrivalTimeSpread (const double eps=1.e-4)
 
double GetGain (const double eps=1.e-4)
 Compute the multiplication factor for the current drift line.
 
double GetLoss (const double eps=1.e-4)
 Compute the attachment loss factor for the current drift line.
 
double GetDriftTime () const
 
void GetAvalancheSize (double &ne, double &ni) const
 
bool FieldLine (const double xi, const double yi, const double zi, std::vector< std::array< float, 3 > > &xl, const bool electron=true)
 
void EnableDebugging ()
 
void DisableDebugging ()
 

Detailed Description

Calculation of drift lines based on macroscopic transport coefficients using Runge-Kutta-Fehlberg integration.

Definition at line 17 of file DriftLineRKF.hh.

Constructor & Destructor Documentation

◆ DriftLineRKF()

Garfield::DriftLineRKF::DriftLineRKF ( )

Constructor.

Definition at line 50 of file DriftLineRKF.cc.

50 {
51 m_t.reserve(1000);
52 m_x.reserve(1000);
53}

◆ ~DriftLineRKF()

Garfield::DriftLineRKF::~DriftLineRKF ( )
inline

Destructor.

Definition at line 22 of file DriftLineRKF.hh.

22{}

Member Function Documentation

◆ DisableDebugging()

void Garfield::DriftLineRKF::DisableDebugging ( )
inline

Definition at line 116 of file DriftLineRKF.hh.

116{ m_debug = false; }

◆ DisablePlotting()

void Garfield::DriftLineRKF::DisablePlotting ( )

Switch off drift line plotting.

Definition at line 90 of file DriftLineRKF.cc.

90{ m_view = nullptr; }

◆ DriftElectron()

bool Garfield::DriftLineRKF::DriftElectron ( const double  x0,
const double  y0,
const double  z0,
const double  t0 
)

Simulate the drift line of an electron with a given starting point.

Definition at line 127 of file DriftLineRKF.cc.

128 {
129 m_particle = Particle::Electron;
130 if (!DriftLine(x0, y0, z0, t0, Particle::Electron, m_t, m_x, m_status)) {
131 return false;
132 }
133 std::vector<double> ne(m_t.size(), 1.);
134 std::vector<double> ni(m_t.size(), 0.);
135 double scale = 1.;
136 if (m_doAvalanche) Avalanche(Particle::Electron, m_x, ne, ni, scale);
137 if (m_doSignal) {
138 ComputeSignal(Particle::Electron, scale * m_scaleE, m_t, m_x, ne);
139 }
140 if (m_doAvalanche && m_doIonTail) AddIonTail(m_t, m_x, ni, scale);
141 return true;
142}

◆ DriftHole()

bool Garfield::DriftLineRKF::DriftHole ( const double  x0,
const double  y0,
const double  z0,
const double  t0 
)

Simulate the drift line of a hole with a given starting point.

Definition at line 191 of file DriftLineRKF.cc.

192 {
193 m_particle = Particle::Hole;
194 if (!DriftLine(x0, y0, z0, t0, Particle::Hole, m_t, m_x, m_status)) {
195 return false;
196 }
197 if (m_doSignal) ComputeSignal(Particle::Hole, m_scaleH, m_t, m_x, {});
198 return true;
199}

◆ DriftIon()

bool Garfield::DriftLineRKF::DriftIon ( const double  x0,
const double  y0,
const double  z0,
const double  t0 
)

Simulate the drift line of an ion with a given starting point.

Definition at line 201 of file DriftLineRKF.cc.

202 {
203 m_particle = Particle::Ion;
204 if (!DriftLine(x0, y0, z0, t0, Particle::Ion, m_t, m_x, m_status)) {
205 return false;
206 }
207 if (m_doSignal) ComputeSignal(Particle::Ion, m_scaleI, m_t, m_x, {});
208 return true;
209}

◆ DriftNegativeIon()

bool Garfield::DriftLineRKF::DriftNegativeIon ( const double  x0,
const double  y0,
const double  z0,
const double  t0 
)

Simulate the drift line of an ion with a given starting point, assuming that it has negative charge.

Definition at line 211 of file DriftLineRKF.cc.

212 {
213
214 m_particle = Particle::NegativeIon;
215 if (!DriftLine(x0, y0, z0, t0, Particle::NegativeIon, m_t, m_x, m_status)) {
216 return false;
217 }
218 if (m_doSignal) {
219 ComputeSignal(Particle::NegativeIon, m_scaleI, m_t, m_x, {});
220 }
221 return true;
222}

◆ DriftPositron()

bool Garfield::DriftLineRKF::DriftPositron ( const double  x0,
const double  y0,
const double  z0,
const double  t0 
)

Simulate the drift line of an electron with a given starting point, assuming that it has positive charge.

Definition at line 178 of file DriftLineRKF.cc.

179 {
180
181 m_particle = Particle::Positron;
182 if (!DriftLine(x0, y0, z0, t0, Particle::Positron, m_t, m_x, m_status)) {
183 return false;
184 }
185 if (m_doSignal) {
186 ComputeSignal(Particle::Positron, m_scaleE, m_t, m_x, {});
187 }
188 return true;
189}

◆ EnableAvalanche()

void Garfield::DriftLineRKF::EnableAvalanche ( const bool  on = true)
inline

Enable/disable simulation electron multiplication (default: on).

Definition at line 58 of file DriftLineRKF.hh.

58{ m_doAvalanche = on; }

◆ EnableDebugging()

void Garfield::DriftLineRKF::EnableDebugging ( )
inline

Definition at line 115 of file DriftLineRKF.hh.

115{ m_debug = true; }

◆ EnableIonTail()

void Garfield::DriftLineRKF::EnableIonTail ( const bool  on = true)
inline

Enable/disable simulation of the ion tail (default: off).

Definition at line 60 of file DriftLineRKF.hh.

60{ m_doIonTail = on; }

◆ EnablePlotting()

void Garfield::DriftLineRKF::EnablePlotting ( ViewDrift view)

Switch on drift line plotting.

Definition at line 82 of file DriftLineRKF.cc.

82 {
83 if (!view) {
84 std::cerr << m_className << "::EnablePlotting: Null pointer.\n";
85 return;
86 }
87 m_view = view;
88}

◆ EnableSignalCalculation()

void Garfield::DriftLineRKF::EnableSignalCalculation ( const bool  on = true)
inline

Switch on/off calculation of induced currents (default: enabled).

Definition at line 33 of file DriftLineRKF.hh.

33{ m_doSignal = on; }

◆ FieldLine()

bool Garfield::DriftLineRKF::FieldLine ( const double  xi,
const double  yi,
const double  zi,
std::vector< std::array< float, 3 > > &  xl,
const bool  electron = true 
)

Compute an electric field line.

Parameters
xi,yi,zistarting point
xlpoints along the field line
electronflag to set the direction in which to follow the field

Definition at line 1603 of file DriftLineRKF.cc.

1605 {
1606
1607 xl.clear();
1608
1609 // Check if the sensor is defined.
1610 if (!m_sensor) {
1611 std::cerr << m_className << "::FieldLine: Sensor is not defined.\n";
1612 return false;
1613 }
1614
1615 // Get the sensor's bounding box.
1616 double xmin = 0., xmax = 0.;
1617 double ymin = 0., ymax = 0.;
1618 double zmin = 0., zmax = 0.;
1619 bool bbox = m_sensor->GetArea(xmin, ymin, zmin, xmax, ymax, zmax);
1620
1621 // Make sure the initial position is at a valid location.
1622 double ex = 0., ey = 0., ez = 0.;
1623 Medium* medium = nullptr;
1624 int stat = 0;
1625 m_sensor->ElectricField(xi, yi, zi, ex, ey, ez, medium, stat);
1626 if (!medium || stat != 0) {
1627 std::cerr << m_className << "::FieldLine:\n"
1628 << " No valid field at initial position.\n";
1629 return false;
1630 }
1631 Vec x0 = {xi, yi, zi};
1632 Vec f0 = {ex, ey, ez};
1633 if (electron) for (auto& f : f0) f *= -1;
1634
1635 // Set the numerical constants for the RKF integration.
1636 constexpr double c10 = 214. / 891.;
1637 constexpr double c11 = 1. / 33.;
1638 constexpr double c12 = 650. / 891.;
1639 constexpr double c20 = 533. / 2106.;
1640 constexpr double c22 = 800. / 1053.;
1641 constexpr double c23 = -1. / 78.;
1642
1643 constexpr double b10 = 1. / 4.;
1644 constexpr double b20 = -189. / 800.;
1645 constexpr double b21 = 729. / 800.;
1646 constexpr double b30 = 214. / 891.;
1647 constexpr double b31 = 1. / 33.;
1648 constexpr double b32 = 650. / 891.;
1649
1650 const double fmag0 = Mag(f0);
1651 if (fmag0 < Small) {
1652 std::cerr << m_className << "::FieldLine:\n"
1653 << " Zero field at initial position.\n";
1654 return false;
1655 }
1656
1657 // Initialise time step and previous time step.
1658 double h = m_accuracy / fmag0;
1659 double hprev = h;
1660
1661 // Set the initial point.
1662 xl.push_back({float(x0[0]), float(x0[1]), float(x0[2])});
1663
1664 int initCycle = 3;
1665 bool ok = true;
1666 while (ok) {
1667 // Get the field at the first probe point.
1668 Vec x1 = x0;
1669 for (unsigned int i = 0; i < 3; ++i) {
1670 x1[i] += h * b10 * f0[i];
1671 }
1672 m_sensor->ElectricField(x1[0], x1[1], x1[2], ex, ey, ez, medium, stat);
1673 if (stat != 0) {
1674 if (m_debug) {
1675 std::cout << m_className << "::FieldLine: Point 1 outside.\n";
1676 }
1677 Terminate(x0, x1, xl);
1678 return true;
1679 }
1680 Vec f1 = {ex, ey, ez};
1681 if (electron) for (auto& f : f1) f *= -1;
1682 // Get the field at the second probe point.
1683 Vec x2 = x0;
1684 for (unsigned int i = 0; i < 3; ++i) {
1685 x2[i] += h * (b20 * f0[i] + b21 * f1[i]);
1686 }
1687 m_sensor->ElectricField(x2[0], x2[1], x2[2], ex, ey, ez, medium, stat);
1688 if (stat != 0) {
1689 if (m_debug) {
1690 std::cout << m_className << "::FieldLine: Point 2 outside.\n";
1691 }
1692 Terminate(x0, x2, xl);
1693 return true;
1694 }
1695 Vec f2 = {ex, ey, ez};
1696 if (electron) for (auto& f : f2) f *= -1;
1697 // Get the field at the third probe point.
1698 Vec x3 = x0;
1699 for (unsigned int i = 0; i < 3; ++i) {
1700 x3[i] += h * (b30 * f0[i] + b31 * f1[i] + b32 * f2[i]);
1701 }
1702 m_sensor->ElectricField(x3[0], x3[1], x3[2], ex, ey, ez, medium, stat);
1703 if (stat != 0) {
1704 if (m_debug) {
1705 std::cout << m_className << "::FieldLine: Point 3 outside.\n";
1706 }
1707 Terminate(x0, x3, xl);
1708 return true;
1709 }
1710 Vec f3 = {ex, ey, ez};
1711 if (electron) for (auto& f : f3) f *= -1;
1712 // Check if we crossed a wire.
1713 double xw = 0., yw = 0., zw = 0., rw = 0.;
1714 if (m_sensor->IsWireCrossed(x0[0], x0[1], x0[2],
1715 x1[0], x1[1], x1[2], xw, yw, zw, false, rw) ||
1716 m_sensor->IsWireCrossed(x0[0], x0[1], x0[2],
1717 x2[0], x2[1], x2[2], xw, yw, zw, false, rw) ||
1718 m_sensor->IsWireCrossed(x0[0], x0[1], x0[2],
1719 x3[0], x3[1], x3[2], xw, yw, zw, false, rw)) {
1720 // TODO!
1721 xl.push_back({float(xw), float(yw), float(zw)});
1722 return true;
1723 // Drift to wire.
1724 if (h > Small) {
1725 h *= 0.5;
1726 continue;
1727 } else {
1728 std::cerr << m_className << "::FieldLine: Step size too small. Stop.\n";
1729 return false;
1730 }
1731 }
1732 // Calculate the correction terms.
1733 Vec phi1 = {0., 0., 0.};
1734 Vec phi2 = {0., 0., 0.};
1735 for (unsigned int i = 0; i < 3; ++i) {
1736 phi1[i] = c10 * f0[i] + c11 * f1[i] + c12 * f2[i];
1737 phi2[i] = c20 * f0[i] + c22 * f2[i] + c23 * f3[i];
1738 }
1739 // Check if the step length is valid.
1740 const double phi1mag = Mag(phi1);
1741 if (phi1mag < Small) {
1742 std::cerr << m_className << "::FieldLine: Step has zero length. Stop.\n";
1743 break;
1744 } else if (m_useStepSizeLimit && h * phi1mag > m_maxStepSize) {
1745 if (m_debug) {
1746 std::cout << m_className << "::FieldLine: Step is considered too long. "
1747 << "H is reduced.\n";
1748 }
1749 h = 0.5 * m_maxStepSize / phi1mag;
1750 continue;
1751 } else if (bbox) {
1752 // Don't allow h to become too large.
1753 if (h * fabs(phi1[0]) > 0.1 * fabs(xmax - xmin) ||
1754 h * fabs(phi1[1]) > 0.1 * fabs(ymax - ymin)) {
1755 h *= 0.5;
1756 if (m_debug) {
1757 std::cout << m_className << "::FieldLine: Step is considered too long. "
1758 << "H is divided by two.\n";
1759 }
1760 continue;
1761 }
1762 }
1763 if (m_debug) std::cout << m_className << "::FieldLine: Step size ok.\n";
1764 // Update the position.
1765 for (unsigned int i = 0; i < 3; ++i) x0[i] += h * phi1[i];
1766 // Check the new position.
1767 m_sensor->ElectricField(x0[0], x0[1], x0[2], ex, ey, ez, medium, stat);
1768 if (stat != 0) {
1769 // The new position is not inside a valid drift medium.
1770 // Terminate the drift line.
1771 if (m_debug) {
1772 std::cout << m_className << "::FieldLine: Point outside. Terminate.\n";
1773 }
1774 std::array<double, 3> xp = {xl.back()[0], xl.back()[1], xl.back()[2]};
1775 Terminate(xp, x0, xl);
1776 return true;
1777 }
1778 // Add the new point to the drift line.
1779 xl.push_back({float(x0[0]), float(x0[1]), float(x0[2])});
1780 // Adjust the step size according to the accuracy of the two estimates.
1781 hprev = h;
1782 const double dphi = fabs(phi1[0] - phi2[0]) + fabs(phi1[1] - phi2[1]) +
1783 fabs(phi1[2] - phi2[2]);
1784 if (dphi > 0) {
1785 h = sqrt(h * m_accuracy / dphi);
1786 if (m_debug) {
1787 std::cout << m_className << "::FieldLine: Adapting H to " << h << ".\n";
1788 }
1789 } else {
1790 h *= 2;
1791 if (m_debug) {
1792 std::cout << m_className << "::FieldLine: H increased by factor two.\n";
1793 }
1794 }
1795 // Make sure that H is different from zero; this should always be ok.
1796 if (h < Small) {
1797 std::cerr << m_className << "::FieldLine: Step size is zero. Stop.\n";
1798 return false;
1799 }
1800 // Check the initial step size.
1801 if (initCycle > 0 && h < 0.2 * hprev) {
1802 if (m_debug) {
1803 std::cout << m_className << "::FieldLine: Reinitialise step size.\n";
1804 }
1805 --initCycle;
1806 x0 = {xi, yi, zi};
1807 xl.clear();
1808 xl.push_back({float(xi), float(yi), float(zi)});
1809 continue;
1810 }
1811 initCycle = 0;
1812 // Don't allow H to grow too quickly
1813 if (h > 10 * hprev) {
1814 h = 10 * hprev;
1815 if (m_debug) {
1816 std::cout << m_className << "::FieldLine: H restricted to 10 times "
1817 << "the previous value.\n";
1818 }
1819 }
1820 // Stop in case H tends to become too small.
1821 if (h * (fabs(phi1[0]) + fabs(phi1[1]) + fabs(phi1[2])) < m_accuracy) {
1822 std::cerr << m_className << "::FieldLine: Step size has become smaller "
1823 << "than int. accuracy. Stop.\n";
1824 return false;
1825 }
1826 // Update the field.
1827 f0 = f3;
1828 }
1829 return true;
1830}
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).
Definition: Sensor.cc:65
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
bool GetArea(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Return the current user area.
Definition: Sensor.cc:228
std::array< double, 3 > Vec
Definition: DriftLineRKF.cc:48
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:615
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314

Referenced by Garfield::ViewField::PlotFieldLines().

◆ GetArrivalTimeSpread()

double Garfield::DriftLineRKF::GetArrivalTimeSpread ( const double  eps = 1.e-4)

Compute the sigma of the arrival time distribution for the current drift line by integrating the longitudinal diffusion coefficient.

Definition at line 680 of file DriftLineRKF.cc.

680 {
681
682 // -----------------------------------------------------------------------
683 // DLCDF1 - Routine returning the integrated diffusion coefficient of
684 // the current drift line. The routine uses an adaptive
685 // Simpson integration.
686 // -----------------------------------------------------------------------
687
688 const unsigned int nPoints = m_x.size();
689 // Return straight away if there is only one point.
690 if (nPoints < 2) return 0.;
691 const Particle particle = m_particle;
692
693 // First get a rough estimate of the result.
694 double crude = 0.;
695 double varPrev = 0.;
696 for (unsigned int i = 0; i < nPoints; ++i) {
697 // Get the drift velocity and diffusion coefficients at this step.
698 double ex = 0., ey = 0., ez = 0.;
699 double bx = 0., by = 0., bz = 0.;
700 Medium* medium = nullptr;
701 if (GetField(m_x[i], ex, ey, ez, bx, by, bz, medium) != 0) {
702 std::cerr << m_className << "::GetArrivalTimeSpread:\n"
703 << " Invalid drift line point " << i << ".\n";
704 continue;
705 }
706 Vec v;
707 if (!GetVelocity(ex, ey, ez, bx, by, bz, medium, particle, v)) {
708 std::cerr << m_className << "::GetArrivalTimeSpread:\n"
709 << " Cannot retrieve drift velocity at point " << i << ".\n";
710 continue;
711 }
712 const double speed = Mag(v);
713 if (speed < Small) {
714 std::cerr << m_className << "::GetArrivalTimeSpread:\n"
715 << " Zero drift velocity at point " << i << ".\n";
716 continue;
717 }
718 double dl = 0., dt = 0.;
719 if (!GetDiffusion(ex, ey, ez, bx, by, bz, medium, particle, dl, dt)) {
720 std::cerr << m_className << "::GetArrivalTimeSpread:\n"
721 << " Cannot retrieve diffusion at point " << i << ".\n";
722 continue;
723 }
724 const double sigma = dl / speed;
725 const double var = sigma * sigma;
726 if (i > 0) {
727 const auto& x = m_x[i];
728 const auto& xPrev = m_x[i - 1];
729 const double d = Mag(x[0] - xPrev[0], x[1] - xPrev[1], x[2] - xPrev[2]);
730 crude += 0.5 * d * (var + varPrev);
731 }
732 varPrev = var;
733 }
734 crude = sqrt(crude);
735
736 const double tol = eps * crude;
737 double sum = 0.;
738 for (unsigned int i = 0; i < nPoints - 1; ++i) {
739 sum += IntegrateDiffusion(m_x[i], m_x[i + 1], particle, tol);
740 }
741 return sqrt(sum);
742}

◆ GetAvalancheSize()

void Garfield::DriftLineRKF::GetAvalancheSize ( double &  ne,
double &  ni 
) const
inline

Definition at line 104 of file DriftLineRKF.hh.

104{ ne = m_nE; ni = m_nI; }

◆ GetDriftLinePoint()

void Garfield::DriftLineRKF::GetDriftLinePoint ( const unsigned int  i,
double &  x,
double &  y,
double &  z,
double &  t 
) const

Get the coordinates and time of a point along the most recent drift line.

Definition at line 1234 of file DriftLineRKF.cc.

1235 {
1236 if (i >= m_x.size()) {
1237 std::cerr << m_className << "::GetDriftLinePoint: Index out of range.\n";
1238 return;
1239 }
1240
1241 const auto& p = m_x[i];
1242 x = p[0];
1243 y = p[1];
1244 z = p[2];
1245 t = m_t[i];
1246}

◆ GetDriftTime()

double Garfield::DriftLineRKF::GetDriftTime ( ) const
inline

Definition at line 102 of file DriftLineRKF.hh.

102{ return m_t.empty() ? 0. : m_t.back(); }

◆ GetEndPoint()

void Garfield::DriftLineRKF::GetEndPoint ( double &  x,
double &  y,
double &  z,
double &  t,
int &  st 
) const

Get the end point and status flag of the most recent drift line.

Definition at line 1219 of file DriftLineRKF.cc.

1220 {
1221 if (m_x.empty()) {
1222 x = y = z = t = 0.;
1223 stat = m_status;
1224 return;
1225 }
1226 const auto& p = m_x.back();
1227 x = p[0];
1228 y = p[1];
1229 z = p[2];
1230 t = m_t.back();
1231 stat = m_status;
1232}

◆ GetGain()

double Garfield::DriftLineRKF::GetGain ( const double  eps = 1.e-4)

Compute the multiplication factor for the current drift line.

Definition at line 744 of file DriftLineRKF.cc.

744 {
745
746 // -----------------------------------------------------------------------
747 // DLCTW1 - Routine returning the multiplication factor for the current
748 // drift line. The routine uses an adaptive Simpson style
749 // integration.
750 // -----------------------------------------------------------------------
751
752 const unsigned int nPoints = m_x.size();
753 // Return straight away if there is only one point.
754 if (nPoints < 2) return 1.;
755 const Particle particle = m_particle;
756 if (particle == Particle::Ion) return 1.;
757 if (m_status == StatusCalculationAbandoned) return 1.;
758
759 // First get a rough estimate of the result.
760 double crude = 0.;
761 double alphaPrev = 0.;
762 for (unsigned int i = 0; i < nPoints; ++i) {
763 // Get the Townsend coefficient at this step.
764 double ex = 0., ey = 0., ez = 0.;
765 double bx = 0., by = 0., bz = 0.;
766 Medium* medium = nullptr;
767 if (GetField(m_x[i], ex, ey, ez, bx, by, bz, medium) != 0) {
768 std::cerr << m_className << "::GetGain:\n"
769 << " Invalid drift line point " << i << ".\n";
770 continue;
771 }
772 double alpha = 0.;
773 if (!GetAlpha(ex, ey, ez, bx, by, bz, medium, particle, alpha)) {
774 std::cerr << m_className << "::GetGain:\n"
775 << " Cannot retrieve alpha at point " << i << ".\n";
776 continue;
777 }
778 if (i > 0) {
779 const auto& x = m_x[i];
780 const auto& xPrev = m_x[i - 1];
781 const double d = Mag(x[0] - xPrev[0], x[1] - xPrev[1], x[2] - xPrev[2]);
782 crude += 0.5 * d * (alpha + alphaPrev);
783 }
784 alphaPrev = alpha;
785 }
786 // Stop if the rough estimate is negligibly small.
787 if (crude < Small) return 1.;
788
789 // Calculate the integration tolerance based on the rough estimate.
790 const double tol = eps * crude;
791 double sum = 0.;
792 for (unsigned int i = 0; i < nPoints - 1; ++i) {
793 sum += IntegrateAlpha(m_x[i], m_x[i + 1], particle, tol);
794 }
795 return exp(sum);
796}
DoubleAc exp(const DoubleAc &f)
Definition: DoubleAc.cpp:377

◆ GetLoss()

double Garfield::DriftLineRKF::GetLoss ( const double  eps = 1.e-4)

Compute the attachment loss factor for the current drift line.

Definition at line 798 of file DriftLineRKF.cc.

798 {
799
800 // -----------------------------------------------------------------------
801 // DLCAT1 - Routine returning the attachment losses for the current
802 // drift line. The routine uses an adaptive Simpson style
803 // integration.
804 // -----------------------------------------------------------------------
805
806 const unsigned int nPoints = m_x.size();
807 // Return straight away if there is only one point.
808 if (nPoints < 2) return 1.;
809 const Particle particle = m_particle;
810 if (particle == Particle::Ion) return 1.;
811 if (m_status == StatusCalculationAbandoned) return 1.;
812
813 // First get a rough estimate of the result.
814 double crude = 0.;
815 double etaPrev = 0.;
816 for (unsigned int i = 0; i < nPoints; ++i) {
817 // Get the Townsend coefficient at this step.
818 double ex = 0., ey = 0., ez = 0.;
819 double bx = 0., by = 0., bz = 0.;
820 Medium* medium = nullptr;
821 if (GetField(m_x[i], ex, ey, ez, bx, by, bz, medium) != 0) {
822 std::cerr << m_className << "::GetLoss:\n"
823 << " Invalid drift line point " << i << ".\n";
824 continue;
825 }
826 double eta = 0.;
827 if (!GetEta(ex, ey, ez, bx, by, bz, medium, particle, eta)) {
828 std::cerr << m_className << "::GetLoss:\n"
829 << " Cannot retrieve eta at point " << i << ".\n";
830 continue;
831 }
832 if (i > 0) {
833 const auto& x = m_x[i];
834 const auto& xPrev = m_x[i - 1];
835 const double d = Mag(x[0] - xPrev[0], x[1] - xPrev[1], x[2] - xPrev[2]);
836 crude += 0.5 * d * (eta + etaPrev);
837 }
838 etaPrev = eta;
839 }
840
841 // Calculate the integration tolerance based on the rough estimate.
842 const double tol = eps * crude;
843 double sum = 0.;
844 for (unsigned int i = 0; i < nPoints - 1; ++i) {
845 sum += IntegrateEta(m_x[i], m_x[i + 1], particle, tol);
846 }
847 return exp(-sum);
848}

◆ GetNumberOfDriftLinePoints()

unsigned int Garfield::DriftLineRKF::GetNumberOfDriftLinePoints ( ) const
inline

Get the number of points of the most recent drift line.

Definition at line 90 of file DriftLineRKF.hh.

90{ return m_x.size(); }

◆ PrintDriftLine()

void Garfield::DriftLineRKF::PrintDriftLine ( ) const

Print the trajectory of the most recent drift line.

Definition at line 1192 of file DriftLineRKF.cc.

1192 {
1193
1194 std::cout << m_className << "::PrintDriftLine:\n";
1195 if (m_x.empty()) {
1196 std::cout << " No drift line present.\n";
1197 return;
1198 }
1199 if (m_particle == Particle::Electron) {
1200 std::cout << " Particle: electron\n";
1201 } else if (m_particle == Particle::Ion) {
1202 std::cout << " Particle: ion\n";
1203 } else if (m_particle == Particle::Hole) {
1204 std::cout << " Particle: hole\n";
1205 } else {
1206 std::cout << " Particle: unknown\n";
1207 }
1208 std::cout << " Status: " << m_status << "\n"
1209 << " Step time [ns] "
1210 << "x [cm] y [cm] z [cm]\n";
1211 const unsigned int nPoints = m_x.size();
1212 for (unsigned int i = 0; i < nPoints; ++i) {
1213 std::printf("%6d %15.7f %15.7f %15.7f %15.7f\n",
1214 i, m_t[i], m_x[i][0], m_x[i][1], m_x[i][2]);
1215 }
1216
1217}

◆ RejectKinks()

void Garfield::DriftLineRKF::RejectKinks ( const bool  on = true)
inline

Request (or not) the drift line calculation to be aborted if the drift line makes a bend sharper than 90 degrees.

Definition at line 48 of file DriftLineRKF.hh.

48{ m_rejectKinks = on; }

◆ SetElectronSignalScalingFactor()

void Garfield::DriftLineRKF::SetElectronSignalScalingFactor ( const double  scale)
inline

Set multiplication factor for the signal induced by electrons.

Definition at line 51 of file DriftLineRKF.hh.

51{ m_scaleE = scale; }

◆ SetGainFluctuationsFixed()

void Garfield::DriftLineRKF::SetGainFluctuationsFixed ( const double  gain = -1.)

Do not randomize the avalanche size.

Definition at line 92 of file DriftLineRKF.cc.

92 {
93
94 if (gain > 1.) {
95 std::cout << m_className << "::SetGainFluctuationsFixed: "
96 << "Avalanche size set to " << gain << ".\n";
97 } else {
98 std::cout << m_className << "::SetGainFluctuationsFixed:\n "
99 << "Avalanche size will be given by "
100 << "the integrated Townsend coefficient.\n";
101 }
102 m_gain = gain;
103 m_gainFluctuations = GainFluctuations::None;
104}

◆ SetGainFluctuationsPolya()

void Garfield::DriftLineRKF::SetGainFluctuationsPolya ( const double  theta,
const double  mean = -1. 
)

Sample the avalanche size from a Polya distribution with shape parameter theta.

Definition at line 106 of file DriftLineRKF.cc.

107 {
108
109 if (theta < 0.) {
110 std::cerr << m_className << "::SetGainFluctuationsPolya: "
111 << "Shape parameter must be >= 0.\n";
112 return;
113 }
114 if (mean > 1.) {
115 std::cout << m_className << "::SetGainFluctuationsPolya: "
116 << "Mean avalanche size set to " << mean << ".\n";
117 } else {
118 std::cout << m_className << "::SetGainFluctuationsPolya:\n "
119 << "Mean avalanche size will be given by "
120 << "the integrated Townsend coefficient.\n";
121 }
122 m_gain = mean;
123 m_theta = theta;
124 m_gainFluctuations = GainFluctuations::Polya;
125}

◆ SetHoleSignalScalingFactor()

void Garfield::DriftLineRKF::SetHoleSignalScalingFactor ( const double  scale)
inline

Set multiplication factor for the signal induced by holes.

Definition at line 53 of file DriftLineRKF.hh.

53{ m_scaleH = scale; }

◆ SetIntegrationAccuracy()

void Garfield::DriftLineRKF::SetIntegrationAccuracy ( const double  eps)

Set the accuracy of the Runge Kutta Fehlberg drift line integration.

Definition at line 63 of file DriftLineRKF.cc.

63 {
64 if (eps > 0.) {
65 m_accuracy = eps;
66 } else {
67 std::cerr << m_className << "::SetIntegrationAccuracy:\n"
68 << " Accuracy must be greater than zero.\n";
69 }
70}

◆ SetIonSignalScalingFactor()

void Garfield::DriftLineRKF::SetIonSignalScalingFactor ( const double  scale)
inline

Set multiplication factor for the signal induced by ions.

Definition at line 55 of file DriftLineRKF.hh.

55{ m_scaleI = scale; }

◆ SetMaximumStepSize()

void Garfield::DriftLineRKF::SetMaximumStepSize ( const double  ms)

Set the maximum step size that is allowed. By default, there is no limit.

Definition at line 72 of file DriftLineRKF.cc.

72 {
73 if (ms > 0.) {
74 m_maxStepSize = ms;
75 m_useStepSizeLimit = true;
76 } else {
77 std::cerr << m_className << "::SetMaximumStepSize:\n"
78 << " Step size must be greater than zero.\n";
79 }
80}

Referenced by Garfield::ViewField::PlotFieldLines().

◆ SetSensor()

void Garfield::DriftLineRKF::SetSensor ( Sensor s)

Set the sensor.

Definition at line 55 of file DriftLineRKF.cc.

55 {
56 if (!s) {
57 std::cerr << m_className << "::SetSensor: Null pointer.\n";
58 return;
59 }
60 m_sensor = s;
61}

Referenced by Garfield::ViewField::PlotFieldLines().

◆ SetSignalAveragingOrder()

void Garfield::DriftLineRKF::SetSignalAveragingOrder ( const unsigned int  navg)
inline

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

Definition at line 38 of file DriftLineRKF.hh.

38{ m_navg = navg; }

◆ UnsetMaximumStepSize()

void Garfield::DriftLineRKF::UnsetMaximumStepSize ( )
inline

Do not apply an upper limit to the step size that is allowed.

Definition at line 45 of file DriftLineRKF.hh.

45{ m_useStepSizeLimit = false; }

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