Garfield++ 3.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
 
void EnableDebugging ()
 
void DisableDebugging ()
 

Detailed Description

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

Definition at line 18 of file DriftLineRKF.hh.

Constructor & Destructor Documentation

◆ DriftLineRKF()

Garfield::DriftLineRKF::DriftLineRKF ( )

Constructor.

Definition at line 45 of file DriftLineRKF.cc.

45 {
46 m_t.reserve(1000);
47 m_x.reserve(1000);
48}

◆ ~DriftLineRKF()

Garfield::DriftLineRKF::~DriftLineRKF ( )
inline

Destructor.

Definition at line 23 of file DriftLineRKF.hh.

23{}

Member Function Documentation

◆ DisableDebugging()

void Garfield::DriftLineRKF::DisableDebugging ( )
inline

Definition at line 108 of file DriftLineRKF.hh.

108{ m_debug = false; }

◆ DisablePlotting()

void Garfield::DriftLineRKF::DisablePlotting ( )

Switch off drift line plotting.

Definition at line 85 of file DriftLineRKF.cc.

85{ 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 122 of file DriftLineRKF.cc.

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

◆ 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 186 of file DriftLineRKF.cc.

187 {
188 m_particle = Particle::Hole;
189 if (!DriftLine(x0, y0, z0, t0, Particle::Hole, m_t, m_x, m_status)) {
190 return false;
191 }
192 if (m_doSignal) ComputeSignal(Particle::Hole, m_scaleH, m_t, m_x, {});
193 return true;
194}

◆ 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 196 of file DriftLineRKF.cc.

197 {
198 m_particle = Particle::Ion;
199 if (!DriftLine(x0, y0, z0, t0, Particle::Ion, m_t, m_x, m_status)) {
200 return false;
201 }
202 if (m_doSignal) ComputeSignal(Particle::Ion, m_scaleI, m_t, m_x, {});
203 return true;
204}

◆ 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 206 of file DriftLineRKF.cc.

207 {
208
209 m_particle = Particle::NegativeIon;
210 if (!DriftLine(x0, y0, z0, t0, Particle::NegativeIon, m_t, m_x, m_status)) {
211 return false;
212 }
213 if (m_doSignal) {
214 ComputeSignal(Particle::NegativeIon, m_scaleI, m_t, m_x, {});
215 }
216 return true;
217}

◆ 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 173 of file DriftLineRKF.cc.

174 {
175
176 m_particle = Particle::Positron;
177 if (!DriftLine(x0, y0, z0, t0, Particle::Positron, m_t, m_x, m_status)) {
178 return false;
179 }
180 if (m_doSignal) {
181 ComputeSignal(Particle::Positron, m_scaleE, m_t, m_x, {});
182 }
183 return true;
184}

◆ EnableAvalanche()

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

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

Definition at line 59 of file DriftLineRKF.hh.

59{ m_doAvalanche = on; }

◆ EnableDebugging()

void Garfield::DriftLineRKF::EnableDebugging ( )
inline

Definition at line 107 of file DriftLineRKF.hh.

107{ 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 61 of file DriftLineRKF.hh.

61{ m_doIonTail = on; }

◆ EnablePlotting()

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

Switch on drift line plotting.

Definition at line 77 of file DriftLineRKF.cc.

77 {
78 if (!view) {
79 std::cerr << m_className << "::EnablePlotting: Null pointer.\n";
80 return;
81 }
82 m_view = view;
83}

◆ EnableSignalCalculation()

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

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

Definition at line 34 of file DriftLineRKF.hh.

34{ m_doSignal = on; }

◆ 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 676 of file DriftLineRKF.cc.

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

◆ GetAvalancheSize()

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

Definition at line 105 of file DriftLineRKF.hh.

105{ 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 1224 of file DriftLineRKF.cc.

1225 {
1226 if (i >= m_x.size()) {
1227 std::cerr << m_className << "::GetDriftLinePoint: Index out of range.\n";
1228 return;
1229 }
1230
1231 const auto& p = m_x[i];
1232 x = p[0];
1233 y = p[1];
1234 z = p[2];
1235 t = m_t[i];
1236}

◆ GetDriftTime()

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

Definition at line 103 of file DriftLineRKF.hh.

103{ 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 1209 of file DriftLineRKF.cc.

1210 {
1211 if (m_x.empty()) {
1212 x = y = z = t = 0.;
1213 stat = m_status;
1214 return;
1215 }
1216 const auto& p = m_x.back();
1217 x = p[0];
1218 y = p[1];
1219 z = p[2];
1220 t = m_t.back();
1221 stat = m_status;
1222}

◆ GetGain()

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

Compute the multiplication factor for the current drift line.

Definition at line 740 of file DriftLineRKF.cc.

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

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

◆ GetNumberOfDriftLinePoints()

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

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

Definition at line 91 of file DriftLineRKF.hh.

91{ return m_x.size(); }

◆ PrintDriftLine()

void Garfield::DriftLineRKF::PrintDriftLine ( ) const

Print the trajectory of the most recent drift line.

Definition at line 1182 of file DriftLineRKF.cc.

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

◆ 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 49 of file DriftLineRKF.hh.

49{ m_rejectKinks = on; }

◆ SetElectronSignalScalingFactor()

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

Set multiplication factor for the signal induced by electrons.

Definition at line 52 of file DriftLineRKF.hh.

52{ m_scaleE = scale; }

◆ SetGainFluctuationsFixed()

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

Do not randomize the avalanche size.

Definition at line 87 of file DriftLineRKF.cc.

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

◆ 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 101 of file DriftLineRKF.cc.

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

◆ SetHoleSignalScalingFactor()

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

Set multiplication factor for the signal induced by holes.

Definition at line 54 of file DriftLineRKF.hh.

54{ 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 58 of file DriftLineRKF.cc.

58 {
59 if (eps > 0.) {
60 m_accuracy = eps;
61 } else {
62 std::cerr << m_className << "::SetIntegrationAccuracy:\n"
63 << " Accuracy must be greater than zero.\n";
64 }
65}

◆ SetIonSignalScalingFactor()

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

Set multiplication factor for the signal induced by ions.

Definition at line 56 of file DriftLineRKF.hh.

56{ 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 67 of file DriftLineRKF.cc.

67 {
68 if (ms > 0.) {
69 m_maxStepSize = ms;
70 m_useStepSizeLimit = true;
71 } else {
72 std::cerr << m_className << "::SetMaximumStepSize:\n"
73 << " Step size must be greater than zero.\n";
74 }
75}

◆ SetSensor()

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

Set the sensor.

Definition at line 50 of file DriftLineRKF.cc.

50 {
51 if (!s) {
52 std::cerr << m_className << "::SetSensor: Null pointer.\n";
53 return;
54 }
55 m_sensor = s;
56}

◆ 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 39 of file DriftLineRKF.hh.

39{ 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 46 of file DriftLineRKF.hh.

46{ m_useStepSizeLimit = false; }

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