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

Base class for gas media. More...

#include <MediumGas.hh>

+ Inheritance diagram for Garfield::MediumGas:

Classes

struct  ExcLevel
 
struct  IonLevel
 

Public Member Functions

 MediumGas ()
 Constructor.
 
virtual ~MediumGas ()
 Destructor.
 
bool IsGas () const override
 Is this medium a gas?
 
bool SetComposition (const std::string &gas1, const double f1=1., const std::string &gas2="", const double f2=0., const std::string &gas3="", const double f3=0., const std::string &gas4="", const double f4=0., const std::string &gas5="", const double f5=0., const std::string &gas6="", const double f6=0.)
 Set the gas mixture.
 
void GetComposition (std::string &gas1, double &f1, std::string &gas2, double &f2, std::string &gas3, double &f3, std::string &gas4, double &f4, std::string &gas5, double &f5, std::string &gas6, double &f6)
 Retrieve the gas mixture.
 
void GetComponent (const unsigned int i, std::string &label, double &f) override
 Get the name and fraction of a given component.
 
void SetAtomicNumber (const double z) override
 Set the effective atomic number.
 
double GetAtomicNumber () const override
 Get the effective atomic number.
 
void SetAtomicWeight (const double a) override
 Set the effective atomic weight.
 
double GetAtomicWeight () const override
 Get the effective atomic weight.
 
void SetNumberDensity (const double n) override
 Set the number density [cm-3].
 
double GetNumberDensity () const override
 Get the number density [cm-3].
 
void SetMassDensity (const double rho) override
 Set the mass density [g/cm3].
 
double GetMassDensity () const override
 Get the mass density [g/cm3].
 
bool LoadGasFile (const std::string &filename)
 Read table of gas properties (transport parameters) from file.
 
bool WriteGasFile (const std::string &filename)
 Save the present table of gas properties (transport parameters) to a file.
 
bool MergeGasFile (const std::string &filename, const bool replaceOld)
 Read table of gas properties from and merge with the existing dataset.
 
virtual bool EnablePenningTransfer (const double r, const double lambda)
 
virtual bool EnablePenningTransfer (const double r, const double lambda, std::string gasname)
 
virtual void DisablePenningTransfer ()
 Switch the simulation of Penning transfers off globally.
 
virtual bool DisablePenningTransfer (std::string gasname)
 Switch the simulation of Penning transfers off for a given component.
 
virtual void PrintGas ()
 Print information about the present gas mixture and available data.
 
bool LoadIonMobility (const std::string &filename)
 Read a table of ion mobilities as function of electric field from file.
 
bool AdjustTownsendCoefficient ()
 
void ResetTables () override
 Reset all tables of transport parameters.
 
void SetExtrapolationMethodExcitationRates (const std::string &low, const std::string &high)
 
void SetExtrapolationMethodIonisationRates (const std::string &low, const std::string &high)
 
void SetInterpolationMethodExcitationRates (const unsigned int intrp)
 
void SetInterpolationMethodIonisationRates (const unsigned int intrp)
 
double ScaleElectricField (const double e) const override
 
double UnScaleElectricField (const double e) const override
 
double ScaleDiffusion (const double d) const override
 
double ScaleDiffusionTensor (const double d) const override
 
double ScaleTownsend (const double alpha) const override
 
double ScaleAttachment (const double eta) const override
 
double ScaleLorentzAngle (const double lor) const override
 
bool GetPhotoAbsorptionCrossSection (const double e, double &sigma, const unsigned int i) override
 
- Public Member Functions inherited from Garfield::Medium
 Medium ()
 Constructor.
 
virtual ~Medium ()
 Destructor.
 
int GetId () const
 Return the id number of the class instance.
 
const std::string & GetName () const
 Get the medium name/identifier.
 
virtual bool IsGas () const
 Is this medium a gas?
 
virtual bool IsSemiconductor () const
 Is this medium a semiconductor?
 
virtual bool IsConductor () const
 Is this medium a conductor?
 
void SetTemperature (const double t)
 Set the temperature [K].
 
double GetTemperature () const
 Get the temperature [K].
 
void SetPressure (const double p)
 
double GetPressure () const
 
void SetDielectricConstant (const double eps)
 Set the relative static dielectric constant.
 
double GetDielectricConstant () const
 Get the relative static dielectric constant.
 
unsigned int GetNumberOfComponents () const
 Get number of components of the medium.
 
virtual void GetComponent (const unsigned int i, std::string &label, double &f)
 Get the name and fraction of a given component.
 
virtual void SetAtomicNumber (const double z)
 Set the effective atomic number.
 
virtual double GetAtomicNumber () const
 Get the effective atomic number.
 
virtual void SetAtomicWeight (const double a)
 Set the effective atomic weight.
 
virtual double GetAtomicWeight () const
 Get the effective atomic weight.
 
virtual void SetNumberDensity (const double n)
 Set the number density [cm-3].
 
virtual double GetNumberDensity () const
 Get the number density [cm-3].
 
virtual void SetMassDensity (const double rho)
 Set the mass density [g/cm3].
 
virtual double GetMassDensity () const
 Get the mass density [g/cm3].
 
virtual void EnableDrift (const bool on=true)
 Switch electron/ion/hole on/off.
 
virtual void EnablePrimaryIonisation (const bool on=true)
 Make the medium ionisable or non-ionisable.
 
bool IsDriftable () const
 Is charge carrier transport enabled in this medium?
 
bool IsMicroscopic () const
 Does the medium have electron scattering rates?
 
bool IsIonisable () const
 Is charge deposition by charged particles/photon enabled in this medium?
 
void SetW (const double w)
 Set the W value (average energy to produce an electron/ion or e/h pair).
 
double GetW ()
 Get the W value.
 
void SetFanoFactor (const double f)
 Set the Fano factor.
 
double GetFanoFactor ()
 Get the Fano factor.
 
virtual bool ElectronVelocity (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
 Drift velocity [cm / ns].
 
virtual bool ElectronDiffusion (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &dl, double &dt)
 Longitudinal and transverse diffusion coefficients [cm1/2].
 
virtual bool ElectronDiffusion (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double cov[3][3])
 
virtual bool ElectronTownsend (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
 Ionisation coefficient [cm-1].
 
virtual bool ElectronAttachment (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
 Attachment coefficient [cm-1].
 
virtual bool ElectronLorentzAngle (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &lor)
 Lorentz angle.
 
virtual double ElectronMobility ()
 Low-field mobility [cm2 V-1 ns-1].
 
virtual double GetElectronEnergy (const double px, const double py, const double pz, double &vx, double &vy, double &vz, const int band=0)
 Dispersion relation (energy vs. wave vector)
 
virtual void GetElectronMomentum (const double e, double &px, double &py, double &pz, int &band)
 
virtual double GetElectronNullCollisionRate (const int band=0)
 Null-collision rate [ns-1].
 
virtual double GetElectronCollisionRate (const double e, const int band=0)
 Collision rate [ns-1] for given electron energy.
 
virtual bool GetElectronCollision (const double e, int &type, int &level, double &e1, double &dx, double &dy, double &dz, std::vector< std::pair< int, double > > &secondaries, int &ndxc, int &band)
 Sample the collision type. Update energy and direction vector.
 
virtual unsigned int GetNumberOfDeexcitationProducts () const
 
virtual bool GetDeexcitationProduct (const unsigned int i, double &t, double &s, int &type, double &energy) const
 
virtual bool HoleVelocity (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
 Drift velocity [cm / ns].
 
virtual bool HoleDiffusion (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &dl, double &dt)
 Longitudinal and transverse diffusion coefficients [cm1/2].
 
virtual bool HoleDiffusion (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double cov[3][3])
 Diffusion tensor.
 
virtual bool HoleTownsend (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &alpha)
 Ionisation coefficient [cm-1].
 
virtual bool HoleAttachment (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &eta)
 Attachment coefficient [cm-1].
 
virtual double HoleMobility ()
 Low-field mobility [cm2 V-1 ns-1].
 
virtual bool IonVelocity (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &vx, double &vy, double &vz)
 Drift velocity [cm / ns].
 
virtual bool IonDiffusion (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &dl, double &dt)
 Longitudinal and transverse diffusion coefficients [cm1/2].
 
virtual bool IonDissociation (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, double &diss)
 Dissociation coefficient.
 
virtual double IonMobility ()
 Low-field mobility [cm2 V-1 ns-1].
 
void SetFieldGrid (double emin, double emax, const size_t ne, bool logE, double bmin=0., double bmax=0., const size_t nb=1, double amin=HalfPi, double amax=HalfPi, const size_t na=1)
 Set the range of fields to be covered by the transport tables.
 
void SetFieldGrid (const std::vector< double > &efields, const std::vector< double > &bfields, const std::vector< double > &angles)
 Set the fields and E-B angles to be used in the transport tables.
 
void GetFieldGrid (std::vector< double > &efields, std::vector< double > &bfields, std::vector< double > &angles)
 Get the fields and E-B angles used in the transport tables.
 
bool SetElectronVelocityE (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double v)
 Set an entry in the table of drift speeds along E.
 
bool GetElectronVelocityE (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &v)
 Get an entry in the table of drift speeds along E.
 
bool SetElectronVelocityExB (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double v)
 Set an entry in the table of drift speeds along ExB.
 
bool GetElectronVelocityExB (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &v)
 Get an entry in the table of drift speeds along ExB.
 
bool SetElectronVelocityB (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double v)
 Set an entry in the table of drift speeds along Btrans.
 
bool GetElectronVelocityB (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &v)
 Get an entry in the table of drift speeds along Btrans.
 
bool SetElectronLongitudinalDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double dl)
 Set an entry in the table of longitudinal diffusion coefficients.
 
bool GetElectronLongitudinalDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &dl)
 Get an entry in the table of longitudinal diffusion coefficients.
 
bool SetElectronTransverseDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double dt)
 Set an entry in the table of transverse diffusion coefficients.
 
bool GetElectronTransverseDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &dt)
 Get an entry in the table of transverse diffusion coefficients.
 
bool SetElectronTownsend (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double alpha)
 Set an entry in the table of Townsend coefficients.
 
bool GetElectronTownsend (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &alpha)
 Get an entry in the table of Townsend coefficients.
 
bool SetElectronAttachment (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double eta)
 Set an entry in the table of attachment coefficients.
 
bool GetElectronAttachment (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &eta)
 Get an entry in the table of attachment coefficients.
 
bool SetElectronLorentzAngle (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double lor)
 Set an entry in the table of Lorentz angles.
 
bool GetElectronLorentzAngle (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &lor)
 Get an entry in the table of Lorentz angles.
 
bool SetHoleVelocityE (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double v)
 Set an entry in the table of drift speeds along E.
 
bool GetHoleVelocityE (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &v)
 Get an entry in the table of drift speeds along E.
 
bool SetHoleVelocityExB (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double v)
 Set an entry in the table of drift speeds along ExB.
 
bool GetHoleVelocityExB (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &v)
 Get an entry in the table of drift speeds along ExB.
 
bool SetHoleVelocityB (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double v)
 Set an entry in the table of drift speeds along Btrans.
 
bool GetHoleVelocityB (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &v)
 Get an entry in the table of drift speeds along Btrans.
 
bool SetHoleLongitudinalDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double dl)
 Set an entry in the table of longitudinal diffusion coefficients.
 
bool GetHoleLongitudinalDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &dl)
 Get an entry in the table of longitudinal diffusion coefficients.
 
bool SetHoleTransverseDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double dt)
 Set an entry in the table of transverse diffusion coefficients.
 
bool GetHoleTransverseDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &dt)
 Get an entry in the table of transverse diffusion coefficients.
 
bool SetHoleTownsend (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double alpha)
 Set an entry in the table of Townsend coefficients.
 
bool GetHoleTownsend (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &alpha)
 Get an entry in the table of Townsend coefficients.
 
bool SetHoleAttachment (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double eta)
 Set an entry in the table of attachment coefficients.
 
bool GetHoleAttachment (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &eta)
 Get an entry in the table of attachment coefficients.
 
bool SetIonMobility (const std::vector< double > &fields, const std::vector< double > &mobilities)
 
bool SetIonMobility (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double mu)
 Set an entry in the table of ion mobilities.
 
bool GetIonMobility (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &mu)
 Get an entry in the table of ion mobilities.
 
bool SetIonLongitudinalDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double dl)
 Set an entry in the table of longitudinal diffusion coefficients.
 
bool GetIonLongitudinalDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &dl)
 Get an entry in the table of longitudinal diffusion coefficients.
 
bool SetIonTransverseDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double dt)
 Set an entry in the table of transverse diffusion coefficients.
 
bool GetIonTransverseDiffusion (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &dt)
 Get an entry in the table of transverse diffusion coefficients.
 
bool SetIonDissociation (const unsigned int ie, const unsigned int ib, const unsigned int ia, const double diss)
 Set an entry in the table of dissociation coefficients.
 
bool GetIonDissociation (const unsigned int ie, const unsigned int ib, const unsigned int ia, double &diss)
 Get an entry in the table of dissociation coefficients.
 
virtual void ResetTables ()
 Reset all tables of transport parameters.
 
void ResetElectronVelocity ()
 
void ResetElectronDiffusion ()
 
void ResetElectronTownsend ()
 
void ResetElectronAttachment ()
 
void ResetElectronLorentzAngle ()
 
void ResetHoleVelocity ()
 
void ResetHoleDiffusion ()
 
void ResetHoleTownsend ()
 
void ResetHoleAttachment ()
 
void ResetIonMobility ()
 
void ResetIonDiffusion ()
 
void ResetIonDissociation ()
 
void SetExtrapolationMethodVelocity (const std::string &extrLow, const std::string &extrHigh)
 
void SetExtrapolationMethodDiffusion (const std::string &extrLow, const std::string &extrHigh)
 
void SetExtrapolationMethodTownsend (const std::string &extrLow, const std::string &extrHigh)
 
void SetExtrapolationMethodAttachment (const std::string &extrLow, const std::string &extrHigh)
 
void SetExtrapolationMethodIonMobility (const std::string &extrLow, const std::string &extrHigh)
 
void SetExtrapolationMethodIonDissociation (const std::string &extrLow, const std::string &extrHigh)
 
void SetInterpolationMethodVelocity (const unsigned int intrp)
 Set the degree of polynomial interpolation (usually 2).
 
void SetInterpolationMethodDiffusion (const unsigned int intrp)
 
void SetInterpolationMethodTownsend (const unsigned int intrp)
 
void SetInterpolationMethodAttachment (const unsigned int intrp)
 
void SetInterpolationMethodIonMobility (const unsigned int intrp)
 
void SetInterpolationMethodIonDissociation (const unsigned int intrp)
 
virtual double ScaleElectricField (const double e) const
 
virtual double UnScaleElectricField (const double e) const
 
virtual double ScaleVelocity (const double v) const
 
virtual double ScaleDiffusion (const double d) const
 
virtual double ScaleDiffusionTensor (const double d) const
 
virtual double ScaleTownsend (const double alpha) const
 
virtual double ScaleAttachment (const double eta) const
 
virtual double ScaleLorentzAngle (const double lor) const
 
virtual double ScaleDissociation (const double diss) const
 
virtual bool GetOpticalDataRange (double &emin, double &emax, const unsigned int i=0)
 Get the energy range [eV] of the available optical data.
 
virtual bool GetDielectricFunction (const double e, double &eps1, double &eps2, const unsigned int i=0)
 Get the complex dielectric function at a given energy.
 
virtual bool GetPhotoAbsorptionCrossSection (const double e, double &sigma, const unsigned int i=0)
 
virtual double GetPhotonCollisionRate (const double e)
 
virtual bool GetPhotonCollision (const double e, int &type, int &level, double &e1, double &ctheta, int &nsec, double &esec)
 
void EnableDebugging ()
 Switch on/off debugging messages.
 
void DisableDebugging ()
 

Protected Member Functions

bool ReadHeader (std::ifstream &gasfile, int &version, std::bitset< 20 > &gasok, bool &is3d, std::vector< double > &mixture, std::vector< double > &efields, std::vector< double > &bfields, std::vector< double > &angles, std::vector< ExcLevel > &excLevels, std::vector< IonLevel > &ionLevels)
 
void ReadFooter (std::ifstream &gasfile, std::array< unsigned int, 13 > &extrapH, std::array< unsigned int, 13 > &extrapL, std::array< unsigned int, 13 > &interp, unsigned int &thrAlp, unsigned int &thrAtt, unsigned int &thrDis, double &ionDiffL, double &ionDiffT, double &pgas, double &tgas)
 
void ReadRecord3D (std::ifstream &gasfile, double &ve, double &vb, double &vx, double &dl, double &dt, double &alpha, double &alpha0, double &eta, double &mu, double &lor, double &dis, std::array< double, 6 > &dif, std::vector< double > &rexc, std::vector< double > &rion)
 
void ReadRecord1D (std::ifstream &gasfile, double &ve, double &vb, double &vx, double &dl, double &dt, double &alpha, double &alpha0, double &eta, double &mu, double &lor, double &dis, std::array< double, 6 > &dif, std::vector< double > &rexc, std::vector< double > &rion)
 
void InsertE (const int ie, const int ne, const int nb, const int na)
 
void InsertB (const int ib, const int ne, const int nb, const int na)
 
void InsertA (const int ia, const int ne, const int nb, const int na)
 
void ZeroRowE (const int ie, const int nb, const int na)
 
void ZeroRowB (const int ib, const int ne, const int na)
 
void ZeroRowA (const int ia, const int ne, const int nb)
 
bool GetMixture (const std::vector< double > &mixture, const int version, std::vector< std::string > &gasnames, std::vector< double > &percentages) const
 
void GetGasBits (std::bitset< 20 > &gasok) const
 
bool GetGasInfo (const std::string &gasname, double &a, double &z) const
 
std::string GetGasName (const int gasnumber, const int version) const
 
std::string GetGasName (std::string input) const
 
int GetGasNumberGasFile (const std::string &input) const
 
- Protected Member Functions inherited from Garfield::Medium
bool Velocity (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, const std::vector< std::vector< std::vector< double > > > &velE, const std::vector< std::vector< std::vector< double > > > &velB, const std::vector< std::vector< std::vector< double > > > &velX, const double q, double &vx, double &vy, double &vz) const
 
bool Diffusion (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, const std::vector< std::vector< std::vector< double > > > &difL, const std::vector< std::vector< std::vector< double > > > &difT, double &dl, double &dt) const
 
bool Diffusion (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, const std::vector< std::vector< std::vector< std::vector< double > > > > &diff, double cov[3][3]) const
 
bool Alpha (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, const std::vector< std::vector< std::vector< double > > > &tab, unsigned int intp, const unsigned int thr, const std::pair< unsigned int, unsigned int > &extr, double &alpha) const
 
double GetAngle (const double ex, const double ey, const double ez, const double bx, const double by, const double bz, const double e, const double b) const
 
bool Interpolate (const double e, const double b, const double a, const std::vector< std::vector< std::vector< double > > > &table, double &y, const unsigned int intp, const std::pair< unsigned int, unsigned int > &extr) const
 
double Interpolate1D (const double e, const std::vector< double > &table, const std::vector< double > &fields, const unsigned int intpMeth, const std::pair< unsigned int, unsigned int > &extr) const
 
bool SetEntry (const unsigned int i, const unsigned int j, const unsigned int k, const std::string &fcn, std::vector< std::vector< std::vector< double > > > &tab, const double val)
 
bool GetEntry (const unsigned int i, const unsigned int j, const unsigned int k, const std::string &fcn, const std::vector< std::vector< std::vector< double > > > &tab, double &val) const
 
void SetExtrapolationMethod (const std::string &low, const std::string &high, std::pair< unsigned int, unsigned int > &extr, const std::string &fcn)
 
bool GetExtrapolationIndex (std::string str, unsigned int &nb) const
 
unsigned int SetThreshold (const std::vector< std::vector< std::vector< double > > > &tab) const
 
void Clone (std::vector< std::vector< std::vector< double > > > &tab, const std::vector< double > &efields, const std::vector< double > &bfields, const std::vector< double > &angles, const unsigned int intp, const std::pair< unsigned int, unsigned int > &extr, const double init, const std::string &label)
 
void Clone (std::vector< std::vector< std::vector< std::vector< double > > > > &tab, const unsigned int n, const std::vector< double > &efields, const std::vector< double > &bfields, const std::vector< double > &angles, const unsigned int intp, const std::pair< unsigned int, unsigned int > &extr, const double init, const std::string &label)
 
void Init (const size_t nE, const size_t nB, const size_t nA, std::vector< std::vector< std::vector< double > > > &tab, const double val)
 
void Init (const size_t nE, const size_t nB, const size_t nA, const size_t nT, std::vector< std::vector< std::vector< std::vector< double > > > > &tab, const double val)
 

Protected Attributes

std::array< std::string, m_nMaxGasesm_gas
 
std::array< double, m_nMaxGasesm_fraction
 
std::array< double, m_nMaxGasesm_atWeight
 
std::array< double, m_nMaxGasesm_atNum
 
bool m_usePenning = false
 
double m_rPenningGlobal = 0.
 
double m_lambdaPenningGlobal = 0.
 
std::array< double, m_nMaxGasesm_rPenningGas
 
std::array< double, m_nMaxGasesm_lambdaPenningGas
 
double m_pressureTable
 
double m_temperatureTable
 
std::vector< std::vector< std::vector< double > > > m_eAlp0
 
std::vector< std::vector< std::vector< std::vector< double > > > > m_excRates
 
std::vector< std::vector< std::vector< std::vector< double > > > > m_ionRates
 
std::vector< ExcLevelm_excLevels
 
std::vector< IonLevelm_ionLevels
 
std::pair< unsigned int, unsigned int > m_extrExc = {0, 1}
 
std::pair< unsigned int, unsigned int > m_extrIon = {0, 1}
 
unsigned int m_intpExc = 2
 
unsigned int m_intpIon = 2
 
- Protected Attributes inherited from Garfield::Medium
std::string m_className = "Medium"
 
int m_id
 
std::string m_name = ""
 
double m_temperature = 293.15
 
double m_pressure = 760.
 
double m_epsilon = 1.
 
unsigned int m_nComponents = 1
 
double m_z = 1.
 
double m_a = 0.
 
double m_density = 0.
 
bool m_driftable = false
 
bool m_microscopic = false
 
bool m_ionisable = false
 
double m_w = 0.
 
double m_fano = 0.
 
bool m_isChanged = true
 
bool m_debug = false
 
std::vector< double > m_eFields
 
std::vector< double > m_bFields
 
std::vector< double > m_bAngles
 
bool m_tab2d = false
 
std::vector< std::vector< std::vector< double > > > m_eVelE
 
std::vector< std::vector< std::vector< double > > > m_eVelX
 
std::vector< std::vector< std::vector< double > > > m_eVelB
 
std::vector< std::vector< std::vector< double > > > m_eDifL
 
std::vector< std::vector< std::vector< double > > > m_eDifT
 
std::vector< std::vector< std::vector< double > > > m_eAlp
 
std::vector< std::vector< std::vector< double > > > m_eAtt
 
std::vector< std::vector< std::vector< double > > > m_eLor
 
std::vector< std::vector< std::vector< std::vector< double > > > > m_eDifM
 
std::vector< std::vector< std::vector< double > > > m_hVelE
 
std::vector< std::vector< std::vector< double > > > m_hVelX
 
std::vector< std::vector< std::vector< double > > > m_hVelB
 
std::vector< std::vector< std::vector< double > > > m_hDifL
 
std::vector< std::vector< std::vector< double > > > m_hDifT
 
std::vector< std::vector< std::vector< double > > > m_hAlp
 
std::vector< std::vector< std::vector< double > > > m_hAtt
 
std::vector< std::vector< std::vector< std::vector< double > > > > m_hDifM
 
std::vector< std::vector< std::vector< double > > > m_iMob
 
std::vector< std::vector< std::vector< double > > > m_iDifL
 
std::vector< std::vector< std::vector< double > > > m_iDifT
 
std::vector< std::vector< std::vector< double > > > m_iDis
 
unsigned int m_eThrAlp = 0
 
unsigned int m_eThrAtt = 0
 
unsigned int m_hThrAlp = 0
 
unsigned int m_hThrAtt = 0
 
unsigned int m_iThrDis = 0
 
std::pair< unsigned int, unsigned int > m_extrVel = {0, 1}
 
std::pair< unsigned int, unsigned int > m_extrDif = {0, 1}
 
std::pair< unsigned int, unsigned int > m_extrAlp = {0, 1}
 
std::pair< unsigned int, unsigned int > m_extrAtt = {0, 1}
 
std::pair< unsigned int, unsigned int > m_extrLor = {0, 1}
 
std::pair< unsigned int, unsigned int > m_extrMob = {0, 1}
 
std::pair< unsigned int, unsigned int > m_extrDis = {0, 1}
 
unsigned int m_intpVel = 2
 
unsigned int m_intpDif = 2
 
unsigned int m_intpAlp = 2
 
unsigned int m_intpAtt = 2
 
unsigned int m_intpLor = 2
 
unsigned int m_intpMob = 2
 
unsigned int m_intpDis = 2
 

Static Protected Attributes

static constexpr unsigned int m_nMaxGases = 6
 
- Static Protected Attributes inherited from Garfield::Medium
static int m_idCounter = -1
 

Detailed Description

Base class for gas media.

Definition at line 15 of file MediumGas.hh.

Constructor & Destructor Documentation

◆ MediumGas()

Garfield::MediumGas::MediumGas ( )

Constructor.

Definition at line 111 of file MediumGas.cc.

113 m_className = "MediumGas";
114
115 m_gas.fill("");
116 m_fraction.fill(0.);
117 m_atWeight.fill(0.);
118 m_atNum.fill(0.);
119 // Default gas mixture: pure argon
120 m_gas[0] = "Ar";
121 m_fraction[0] = 1.;
122 m_name = m_gas[0];
124
125 m_rPenningGas.fill(0.);
126 m_lambdaPenningGas.fill(0.);
127
128 m_isChanged = true;
129
130 EnableDrift();
132}
bool GetGasInfo(const std::string &gasname, double &a, double &z) const
Definition: MediumGas.cc:2571
std::array< double, m_nMaxGases > m_rPenningGas
Definition: MediumGas.hh:142
std::array< double, m_nMaxGases > m_atNum
Definition: MediumGas.hh:132
double m_temperatureTable
Definition: MediumGas.hh:149
std::array< double, m_nMaxGases > m_atWeight
Definition: MediumGas.hh:131
std::array< double, m_nMaxGases > m_lambdaPenningGas
Definition: MediumGas.hh:144
std::array< std::string, m_nMaxGases > m_gas
Definition: MediumGas.hh:129
std::array< double, m_nMaxGases > m_fraction
Definition: MediumGas.hh:130
double m_pressure
Definition: Medium.hh:517
virtual void EnableDrift(const bool on=true)
Switch electron/ion/hole on/off.
Definition: Medium.hh:67
std::string m_name
Definition: Medium.hh:513
virtual void EnablePrimaryIonisation(const bool on=true)
Make the medium ionisable or non-ionisable.
Definition: Medium.hh:69
Medium()
Constructor.
Definition: Medium.cc:60
std::string m_className
Definition: Medium.hh:506
bool m_isChanged
Definition: Medium.hh:540
double m_temperature
Definition: Medium.hh:515

◆ ~MediumGas()

virtual Garfield::MediumGas::~MediumGas ( )
inlinevirtual

Destructor.

Definition at line 20 of file MediumGas.hh.

20{}

Member Function Documentation

◆ AdjustTownsendCoefficient()

bool Garfield::MediumGas::AdjustTownsendCoefficient ( )

Adjust the Townsend coefficient using the excitation and ionisation rates stored in the gas table and the Penning transfer probabilities.

Definition at line 2505 of file MediumGas.cc.

2505 {
2506
2507 // -----------------------------------------------------------------------
2508 // GASSPT
2509 // -----------------------------------------------------------------------
2510
2511 // Make sure there are Townsend coefficients.
2512 if (m_eAlp.empty() || m_eAlp0.empty()) {
2513 std::cerr << m_className << "::AdjustTownsendCoefficient:\n "
2514 << "Present gas table does not include Townsend coefficients.\n";
2515 return false;
2516 }
2517 // Make sure there are excitation and ionisation rates.
2518 if (m_excLevels.empty() || m_excRates.empty()) {
2519 std::cerr << m_className << "::AdjustTownsendCoefficient:\n "
2520 << "Present gas table does not include excitation rates.\n";
2521 return false;
2522 }
2523 if (m_ionLevels.empty() || m_ionRates.empty()) {
2524 std::cerr << m_className << "::AdjustTownsendCoefficient:\n "
2525 << "Present gas table does not include ionisation rates.\n";
2526 return false;
2527 }
2528 const unsigned int nE = m_eFields.size();
2529 const unsigned int nB = m_bFields.size();
2530 const unsigned int nA = m_bAngles.size();
2531 if (m_debug) {
2532 std::cout << m_className << "::AdjustTownsendCoefficient:\n"
2533 << " Entry Exc. Ion.\n";
2534 }
2535 for (unsigned int i = 0; i < nE; ++i) {
2536 for (unsigned int j = 0; j < nA; ++j) {
2537 for (unsigned int k = 0; k < nB; ++k) {
2538 // Compute total ionisation rate.
2539 double rion = 0.;
2540 for (const auto& ion : m_ionRates) {
2541 rion += ion[j][k][i];
2542 }
2543 // Compute rate of Penning ionisations.
2544 double rexc = 0.;
2545 const unsigned int nexc = m_excLevels.size();
2546 for (unsigned int ie = 0; ie < nexc; ++ie) {
2547 rexc += m_excLevels[ie].prob * m_excRates[ie][j][k][i];
2548 }
2549 if (m_debug) {
2550 std::cout << FmtInt(i, 4) << FmtInt(j, 4) << FmtInt(k, 4)
2551 << FmtFloat(rexc, 12, 5) << FmtFloat(rion, 12, 5) << "\n";
2552 }
2553 // Adjust the Townsend coefficient.
2554 double alpha0 = m_eAlp0[j][k][i];
2555 if (alpha0 < -20.) {
2556 alpha0 = 0.;
2557 } else {
2558 alpha0 = m_pressure * exp(alpha0);
2559 }
2560 double alpha1 = alpha0;
2561 if (rion > 0.) alpha1 *= (rexc + rion) / rion;
2562 m_eAlp[j][k][i] = alpha1 > 0. ? log(alpha1 / m_pressure) : -30.;
2563 }
2564 }
2565 }
2566 // Update the threshold index.
2568 return true;
2569}
std::vector< std::vector< std::vector< std::vector< double > > > > m_excRates
Definition: MediumGas.hh:155
std::vector< IonLevel > m_ionLevels
Definition: MediumGas.hh:172
std::vector< std::vector< std::vector< std::vector< double > > > > m_ionRates
Definition: MediumGas.hh:156
std::vector< ExcLevel > m_excLevels
Definition: MediumGas.hh:166
std::vector< std::vector< std::vector< double > > > m_eAlp0
Definition: MediumGas.hh:152
std::vector< double > m_bFields
Definition: Medium.hh:547
unsigned int SetThreshold(const std::vector< std::vector< std::vector< double > > > &tab) const
Definition: Medium.cc:1146
std::vector< std::vector< std::vector< double > > > m_eAlp
Definition: Medium.hh:558
std::vector< double > m_eFields
Definition: Medium.hh:546
std::vector< double > m_bAngles
Definition: Medium.hh:548
DoubleAc exp(const DoubleAc &f)
Definition: DoubleAc.cpp:377

Referenced by DisablePenningTransfer(), and EnablePenningTransfer().

◆ DisablePenningTransfer() [1/2]

void Garfield::MediumGas::DisablePenningTransfer ( )
virtual

Switch the simulation of Penning transfers off globally.

Reimplemented in Garfield::MediumMagboltz.

Definition at line 2450 of file MediumGas.cc.

2450 {
2451
2452 m_rPenningGlobal = 0.;
2454
2455 m_rPenningGas.fill(0.);
2456 m_lambdaPenningGas.fill(0.);
2457
2458 if (m_excLevels.empty()) return;
2459 for (auto& exc : m_excLevels) {
2460 exc.prob = 0.;
2461 }
2463}
bool AdjustTownsendCoefficient()
Definition: MediumGas.cc:2505
double m_lambdaPenningGlobal
Definition: MediumGas.hh:140

Referenced by Garfield::MediumMagboltz::DisablePenningTransfer().

◆ DisablePenningTransfer() [2/2]

bool Garfield::MediumGas::DisablePenningTransfer ( std::string  gasname)
virtual

Switch the simulation of Penning transfers off for a given component.

Reimplemented in Garfield::MediumMagboltz.

Definition at line 2465 of file MediumGas.cc.

2465 {
2466
2467 // Get the "standard" name of this gas.
2468 gasname = GetGasName(gasname);
2469 if (gasname.empty()) {
2470 std::cerr << m_className << "::DisablePenningTransfer: Unknown gas name.\n";
2471 return false;
2472 }
2473
2474 // Look for this gas in the present gas mixture.
2475 int iGas = -1;
2476 for (unsigned int i = 0; i < m_nComponents; ++i) {
2477 if (m_gas[i] == gasname) {
2478 m_rPenningGas[i] = 0.;
2479 m_lambdaPenningGas[i] = 0.;
2480 iGas = i;
2481 break;
2482 }
2483 }
2484
2485 if (iGas < 0) {
2486 std::cerr << m_className << "::DisablePenningTransfer:\n"
2487 << " Requested gas (" << gasname
2488 << ") is not part of the present gas mixture.\n";
2489 return false;
2490 }
2491
2492 if (m_excLevels.empty()) return true;
2493 for (auto& exc : m_excLevels) {
2494 // Try to extract the gas name from the label.
2495 const auto pos = exc.label.find('-');
2496 if (pos == std::string::npos) continue;
2497 if (GetGasName(exc.label.substr(0, pos)) != gasname) continue;
2498 exc.prob = 0.;
2499 }
2501 return true;
2502}
std::string GetGasName(const int gasnumber, const int version) const
Definition: MediumGas.cc:2740
unsigned int m_nComponents
Definition: Medium.hh:521

◆ EnablePenningTransfer() [1/2]

bool Garfield::MediumGas::EnablePenningTransfer ( const double  r,
const double  lambda 
)
virtual

Switch on simulation of Penning transfers by means of transfer probabilities, for all excitation levels in the mixture.

Parameters
rtransfer probability [0, 1]
lambdaparameter for sampling the distance of the Penning electron with respect to the excitation.

Reimplemented in Garfield::MediumMagboltz.

Definition at line 2321 of file MediumGas.cc.

2322 {
2323
2324 if (r < 0. || r > 1.) {
2325 std::cerr << m_className << "::EnablePenningTransfer:\n"
2326 << " Transfer probability must be in the range [0, 1].\n";
2327 return false;
2328 }
2329
2330 m_rPenningGlobal = r;
2331 m_lambdaPenningGlobal = lambda > Small ? lambda : 0.;
2332
2333 std::cout << m_className << "::EnablePenningTransfer:\n"
2334 << " Global Penning transfer parameters set to:\n"
2335 << " r = " << m_rPenningGlobal << "\n"
2336 << " lambda = " << m_lambdaPenningGlobal << " cm\n";
2337
2338 // Find the min. ionisation energy.
2339 if (m_ionLevels.empty()) {
2340 std::cerr << m_className << "::EnablePenningTransfer:\n Warning: present"
2341 << " gas table has no ionisation rates.\n Ignore this message "
2342 << "if you are using microscopic tracking only.\n";
2343 return true;
2344 }
2345 double minIonPot = -1.;
2346 for (const auto& ion : m_ionLevels) {
2347 if (minIonPot < 0.) {
2348 minIonPot = ion.energy;
2349 } else {
2350 minIonPot = std::min(minIonPot, ion.energy);
2351 }
2352 }
2353
2354 // Update the transfer probabilities of the excitation levels in the table.
2355 unsigned int nLevelsFound = 0;
2356 for (auto& exc : m_excLevels) {
2357 if (exc.energy < minIonPot) continue;
2358 exc.prob = m_rPenningGlobal;
2359 exc.rms = m_lambdaPenningGlobal;
2360 ++nLevelsFound;
2361 }
2362 if (nLevelsFound > 0) {
2363 std::cout << m_className << "::EnablePenningTransfer:\n"
2364 << " Updated transfer probabilities for " << nLevelsFound
2365 << " excitation rates.\n";
2367 } else {
2368 std::cerr << m_className << "::EnablePenningTransfer:\n Warning: present"
2369 << " gas table has no eligible excitation rates.\n Ignore this"
2370 << " message if you are using microscopic tracking only.\n";
2371 }
2372 return true;
2373}

Referenced by Garfield::MediumMagboltz::EnablePenningTransfer().

◆ EnablePenningTransfer() [2/2]

bool Garfield::MediumGas::EnablePenningTransfer ( const double  r,
const double  lambda,
std::string  gasname 
)
virtual

Switch on simulation of Penning transfers by means of transfer probabilities, for all excitations of a given component.

Reimplemented in Garfield::MediumMagboltz.

Definition at line 2375 of file MediumGas.cc.

2376 {
2377
2378 if (r < 0. || r > 1.) {
2379 std::cerr << m_className << "::EnablePenningTransfer:\n"
2380 << " Transfer probability must be in the range [0, 1].\n";
2381 return false;
2382 }
2383
2384 // Get the "standard" name of this gas.
2385 gasname = GetGasName(gasname);
2386 if (gasname.empty()) {
2387 std::cerr << m_className << "::EnablePenningTransfer: Unknown gas name.\n";
2388 return false;
2389 }
2390
2391 // Look for this gas in the present gas mixture.
2392 int iGas = -1;
2393 for (unsigned int i = 0; i < m_nComponents; ++i) {
2394 if (m_gas[i] == gasname) {
2395 m_rPenningGas[i] = r;
2396 m_lambdaPenningGas[i] = lambda > Small ? lambda : 0.;
2397 iGas = i;
2398 break;
2399 }
2400 }
2401
2402 if (iGas < 0) {
2403 std::cerr << m_className << "::EnablePenningTransfer:\n"
2404 << " Requested gas (" << gasname
2405 << ") is not part of the present gas mixture.\n";
2406 return false;
2407 }
2408
2409 // Find the min. ionisation energy.
2410 if (m_ionLevels.empty()) {
2411 std::cerr << m_className << "::EnablePenningTransfer:\n Warning: present"
2412 << " gas table has no ionisation rates.\n Ignore this message"
2413 << " if you are using microscopic tracking only.\n";
2414 return true;
2415 }
2416 double minIonPot = -1.;
2417 for (const auto& ion : m_ionLevels) {
2418 if (minIonPot < 0.) {
2419 minIonPot = ion.energy;
2420 } else {
2421 minIonPot = std::min(minIonPot, ion.energy);
2422 }
2423 }
2424 // Update the transfer probabilities of the excitation levels in the table.
2425 unsigned int nLevelsFound = 0;
2426 for (auto& exc : m_excLevels) {
2427 if (exc.energy < minIonPot) continue;
2428 // Try to extract the gas name from the label.
2429 // TODO: test if this works for all gases and excitation levels.
2430 const auto pos = exc.label.find('-');
2431 if (pos == std::string::npos) continue;
2432 if (GetGasName(exc.label.substr(0, pos)) != gasname) continue;
2433 exc.prob = r;
2434 exc.rms = lambda;
2435 ++nLevelsFound;
2436 }
2437 if (nLevelsFound > 0) {
2438 std::cout << m_className << "::EnablePenningTransfer:\n"
2439 << " Updated transfer probabilities for " << nLevelsFound
2440 << " excitation rates.\n";
2442 } else {
2443 std::cerr << m_className << "::EnablePenningTransfer:\n Warning: present"
2444 << " gas table has no eligible excitation rates.\n Ignore this"
2445 << " message if you are using microscopic tracking only.\n";
2446 }
2447 return true;
2448}

◆ GetAtomicNumber()

double Garfield::MediumGas::GetAtomicNumber ( ) const
overridevirtual

Get the effective atomic number.

Reimplemented from Garfield::Medium.

Definition at line 302 of file MediumGas.cc.

302 {
303 // Effective Z, weighted by the fractions of the components.
304 double z = 0.;
305 for (unsigned int i = 0; i < m_nComponents; ++i) {
306 z += m_atNum[i] * m_fraction[i];
307 }
308 return z;
309}

◆ GetAtomicWeight()

double Garfield::MediumGas::GetAtomicWeight ( ) const
overridevirtual

Get the effective atomic weight.

Reimplemented from Garfield::Medium.

Definition at line 283 of file MediumGas.cc.

283 {
284 // Effective A, weighted by the fractions of the components.
285 double a = 0.;
286 for (unsigned int i = 0; i < m_nComponents; ++i) {
287 a += m_atWeight[i] * m_fraction[i];
288 }
289 return a;
290}

Referenced by GetMassDensity().

◆ GetComponent()

void Garfield::MediumGas::GetComponent ( const unsigned int  i,
std::string &  label,
double &  f 
)
overridevirtual

Get the name and fraction of a given component.

Reimplemented from Garfield::Medium.

Definition at line 246 of file MediumGas.cc.

247 {
248 if (i >= m_nComponents) {
249 std::cerr << m_className << "::GetComponent: Index out of range.\n";
250 label = "";
251 f = 0.;
252 return;
253 }
254
255 label = m_gas[i];
256 f = m_fraction[i];
257}

◆ GetComposition()

void Garfield::MediumGas::GetComposition ( std::string &  gas1,
double &  f1,
std::string &  gas2,
double &  f2,
std::string &  gas3,
double &  f3,
std::string &  gas4,
double &  f4,
std::string &  gas5,
double &  f5,
std::string &  gas6,
double &  f6 
)

Retrieve the gas mixture.

Definition at line 228 of file MediumGas.cc.

231 {
232 gas1 = m_gas[0];
233 gas2 = m_gas[1];
234 gas3 = m_gas[2];
235 gas4 = m_gas[3];
236 gas5 = m_gas[4];
237 gas6 = m_gas[5];
238 f1 = m_fraction[0];
239 f2 = m_fraction[1];
240 f3 = m_fraction[2];
241 f4 = m_fraction[3];
242 f5 = m_fraction[4];
243 f6 = m_fraction[5];
244}

◆ GetGasBits()

void Garfield::MediumGas::GetGasBits ( std::bitset< 20 > &  gasok) const
protected

Definition at line 2047 of file MediumGas.cc.

2047 {
2048
2049 gasok.reset();
2050 if (!m_eVelE.empty()) gasok.set(0);
2051 if (!m_iMob.empty()) gasok.set(1);
2052 if (!m_eDifL.empty()) gasok.set(2);
2053 if (!m_eAlp.empty()) gasok.set(3);
2054 // Cluster size distribution; skipped
2055 if (!m_eAtt.empty()) gasok.set(5);
2056 if (!m_eLor.empty()) gasok.set(6);
2057 if (!m_eDifT.empty()) gasok.set(7);
2058 if (!m_eVelB.empty()) gasok.set(8);
2059 if (!m_eVelX.empty()) gasok.set(9);
2060 if (!m_eDifM.empty()) gasok.set(10);
2061 if (!m_iDis.empty()) gasok.set(11);
2062 // SRIM, HEED; skipped
2063 if (!m_excRates.empty()) gasok.set(14);
2064 if (!m_ionRates.empty()) gasok.set(15);
2065}
std::vector< std::vector< std::vector< double > > > m_eVelE
Definition: Medium.hh:553
std::vector< std::vector< std::vector< double > > > m_eVelX
Definition: Medium.hh:554
std::vector< std::vector< std::vector< double > > > m_eDifL
Definition: Medium.hh:556
std::vector< std::vector< std::vector< double > > > m_eAtt
Definition: Medium.hh:559
std::vector< std::vector< std::vector< double > > > m_eLor
Definition: Medium.hh:560
std::vector< std::vector< std::vector< double > > > m_eDifT
Definition: Medium.hh:557
std::vector< std::vector< std::vector< double > > > m_eVelB
Definition: Medium.hh:555
std::vector< std::vector< std::vector< std::vector< double > > > > m_eDifM
Definition: Medium.hh:562
std::vector< std::vector< std::vector< double > > > m_iMob
Definition: Medium.hh:576
std::vector< std::vector< std::vector< double > > > m_iDis
Definition: Medium.hh:579

Referenced by MergeGasFile(), and WriteGasFile().

◆ GetGasInfo()

bool Garfield::MediumGas::GetGasInfo ( const std::string &  gasname,
double &  a,
double &  z 
) const
protected

Definition at line 2571 of file MediumGas.cc.

2572 {
2573 if (gasname == "CF4") {
2574 a = 12.0107 + 4 * 18.9984032;
2575 z = 6 + 4 * 9;
2576 return true;
2577 } else if (gasname == "Ar") {
2578 a = 39.948;
2579 z = 18;
2580 } else if (gasname == "He") {
2581 a = 4.002602;
2582 z = 2;
2583 } else if (gasname == "He-3") {
2584 a = 3.01602931914;
2585 z = 2;
2586 } else if (gasname == "Ne") {
2587 a = 20.1797;
2588 z = 10;
2589 } else if (gasname == "Kr") {
2590 a = 37.798;
2591 z = 36;
2592 } else if (gasname == "Xe") {
2593 a = 131.293;
2594 z = 54;
2595 } else if (gasname == "CH4") {
2596 a = 12.0107 + 4 * 1.00794;
2597 z = 6 + 4;
2598 } else if (gasname == "C2H6") {
2599 a = 2 * 12.0107 + 6 * 1.00794;
2600 z = 2 * 6 + 6;
2601 } else if (gasname == "C3H8") {
2602 a = 3 * 12.0107 + 8 * 1.00794;
2603 z = 3 * 6 + 8;
2604 } else if (gasname == "iC4H10") {
2605 a = 4 * 12.0107 + 10 * 1.00794;
2606 z = 4 * 6 + 10;
2607 } else if (gasname == "CO2") {
2608 a = 12.0107 + 2 * 15.9994;
2609 z = 6 + 2 * 8;
2610 } else if (gasname == "neoC5H12") {
2611 a = 5 * 12.0107 + 12 * 1.00794;
2612 z = 5 * 6 + 12;
2613 } else if (gasname == "H2O") {
2614 a = 2 * 1.00794 + 15.9994;
2615 z = 2 + 8;
2616 } else if (gasname == "O2") {
2617 a = 2 * 15.9994;
2618 z = 2 * 8;
2619 } else if (gasname == "N2") {
2620 a = 2 * 14.0067;
2621 z = 2 * 7;
2622 } else if (gasname == "NO") {
2623 a = 14.0067 + 15.9994;
2624 z = 7 + 8;
2625 } else if (gasname == "N2O") {
2626 a = 2 * 14.0067 + 15.9994;
2627 z = 2 * 7 + 8;
2628 } else if (gasname == "C2H4") {
2629 a = 2 * 12.0107 + 4 * 1.00794;
2630 z = 2 * 6 + 4;
2631 } else if (gasname == "C2H2") {
2632 a = 2 * 12.0107 + 2 * 1.00794;
2633 z = 2 * 6 + 2;
2634 } else if (gasname == "H2" || gasname == "paraH2") {
2635 a = 2 * 1.00794;
2636 z = 2;
2637 } else if (gasname == "D2" || gasname == "orthoD2") {
2638 a = 2 * 2.01410177785;
2639 z = 2;
2640 } else if (gasname == "CO") {
2641 a = 12.0107 + 15.9994;
2642 z = 6 + 8;
2643 } else if (gasname == "Methylal") {
2644 a = 3 * 12.0107 + 8 * 1.00794 + 2 * 15.9994;
2645 z = 3 * 6 + 8 + 2 * 8;
2646 } else if (gasname == "DME") {
2647 a = 4 * 12.0107 + 10 * 1.00794 + 2 * 15.9994;
2648 z = 4 * 6 + 10 + 2 * 8;
2649 } else if (gasname == "Reid-Step" || gasname == "Mawell-Model" ||
2650 gasname == "Reid-Ramp") {
2651 a = 1.;
2652 z = 1.;
2653 } else if (gasname == "C2F6") {
2654 a = 2 * 12.0107 + 6 * 18.9984032;
2655 z = 2 * 6 + 6 * 9;
2656 } else if (gasname == "SF6") {
2657 a = 32.065 + 6 * 18.9984032;
2658 z = 16 + 6 * 9;
2659 } else if (gasname == "NH3") {
2660 a = 14.0067 + 3 * 1.00794;
2661 z = 7 + 3;
2662 } else if (gasname == "C3H6") {
2663 a = 3 * 12.0107 + 6 * 1.00794;
2664 z = 3 * 6 + 6;
2665 } else if (gasname == "cC3H6") {
2666 a = 3 * 12.0107 + 6 * 1.00794;
2667 z = 3 * 6 + 6;
2668 } else if (gasname == "CH3OH") {
2669 a = 12.0107 + 4 * 1.00794 + 15.9994;
2670 z = 6 + 4 + 8;
2671 } else if (gasname == "C2H5OH") {
2672 a = 2 * 12.0107 + 6 * 1.00794 + 15.9994;
2673 z = 2 * 6 + 6 + 8;
2674 } else if (gasname == "C3H7OH" || gasname == "nC3H7OH") {
2675 a = 3 * 12.0107 + 8 * 1.00794 + 15.9994;
2676 z = 3 * 6 + 8 * 8;
2677 } else if (gasname == "Cs") {
2678 a = 132.9054519;
2679 z = 55;
2680 } else if (gasname == "F2") {
2681 a = 2 * 18.9984032;
2682 z = 2 * 9;
2683 } else if (gasname == "CS2") {
2684 a = 12.0107 + 2 * 32.065;
2685 z = 6 + 2 * 16;
2686 } else if (gasname == "COS") {
2687 a = 12.0107 + 15.9994 + 32.065;
2688 z = 6 + 8 + 16;
2689 } else if (gasname == "CD4") {
2690 a = 12.0107 + 4 * 2.01410177785;
2691 z = 6 + 4;
2692 } else if (gasname == "BF3") {
2693 a = 10.811 + 3 * 18.9984032;
2694 z = 5 + 3 * 9;
2695 } else if (gasname == "C2H2F4") {
2696 a = 2 * 12.0107 + 2 * 1.00794 + 4 * 18.9984032;
2697 z = 2 * 6 + 2 + 4 * 9;
2698 } else if (gasname == "CHF3") {
2699 a = 12.0107 + 1.00794 + 3 * 18.9984032;
2700 z = 6 + 1 + 3 * 9;
2701 } else if (gasname == "CF3Br") {
2702 a = 12.0107 + 3 * 18.9984032 + 79.904;
2703 z = 6 + 3 * 9 + 35;
2704 } else if (gasname == "C3F8") {
2705 a = 3 * 12.0107 + 8 * 18.9984032;
2706 z = 3 * 6 + 8 * 9;
2707 } else if (gasname == "O3") {
2708 a = 3 * 15.9994;
2709 z = 3 * 8;
2710 } else if (gasname == "Hg") {
2711 a = 2 * 200.59;
2712 z = 80;
2713 } else if (gasname == "H2S") {
2714 a = 2 * 1.00794 + 32.065;
2715 z = 2 + 16;
2716 } else if (gasname == "nC4H10") {
2717 a = 4 * 12.0107 + 10 * 1.00794;
2718 z = 4 * 6 + 10;
2719 } else if (gasname == "nC5H12") {
2720 a = 5 * 12.0107 + 12 * 1.00794;
2721 z = 5 * 6 + 12;
2722 } else if (gasname == "N2") {
2723 a = 2 * 14.0067;
2724 z = 2 * 7;
2725 } else if (gasname == "GeH4") {
2726 a = 72.64 + 4 * 1.00794;
2727 z = 32 + 4;
2728 } else if (gasname == "SiH4") {
2729 a = 28.0855 + 4 * 1.00794;
2730 z = 14 + 4;
2731 } else {
2732 a = 0.;
2733 z = 0.;
2734 return false;
2735 }
2736
2737 return true;
2738}

Referenced by LoadGasFile(), MediumGas(), and SetComposition().

◆ GetGasName() [1/2]

std::string Garfield::MediumGas::GetGasName ( const int  gasnumber,
const int  version 
) const
protected

Definition at line 2740 of file MediumGas.cc.

2740 {
2741
2742 switch (gasnumber) {
2743 case 1:
2744 return "CF4";
2745 break;
2746 case 2:
2747 return "Ar";
2748 break;
2749 case 3:
2750 return "He";
2751 break;
2752 case 4:
2753 return "He-3";
2754 break;
2755 case 5:
2756 return "Ne";
2757 break;
2758 case 6:
2759 return "Kr";
2760 break;
2761 case 7:
2762 return "Xe";
2763 break;
2764 case 8:
2765 return "CH4";
2766 break;
2767 case 9:
2768 return "C2H6";
2769 break;
2770 case 10:
2771 return "C3H8";
2772 break;
2773 case 11:
2774 return "iC4H10";
2775 break;
2776 case 12:
2777 return "CO2";
2778 break;
2779 case 13:
2780 return "neoC5H12";
2781 break;
2782 case 14:
2783 return "H2O";
2784 break;
2785 case 15:
2786 return "O2";
2787 break;
2788 case 16:
2789 return "N2";
2790 break;
2791 case 17:
2792 return "NO";
2793 break;
2794 case 18:
2795 return "N2O";
2796 break;
2797 case 19:
2798 return "C2H4";
2799 break;
2800 case 20:
2801 return "C2H2";
2802 break;
2803 case 21:
2804 return "H2";
2805 break;
2806 case 22:
2807 return "D2";
2808 break;
2809 case 23:
2810 return "CO";
2811 break;
2812 case 24:
2813 return "Methylal";
2814 break;
2815 case 25:
2816 return "DME";
2817 break;
2818 case 26:
2819 return "Reid-Step";
2820 break;
2821 case 27:
2822 return "Maxwell-Model";
2823 break;
2824 case 28:
2825 return "Reid-Ramp";
2826 break;
2827 case 29:
2828 return "C2F6";
2829 break;
2830 case 30:
2831 return "SF6";
2832 break;
2833 case 31:
2834 return "NH3";
2835 break;
2836 case 32:
2837 return "C3H6";
2838 break;
2839 case 33:
2840 return "cC3H6";
2841 break;
2842 case 34:
2843 return "CH3OH";
2844 break;
2845 case 35:
2846 return "C2H5OH";
2847 break;
2848 case 36:
2849 return "C3H7OH";
2850 break;
2851 case 37:
2852 return "Cs";
2853 break;
2854 case 38:
2855 return "F2";
2856 break;
2857 case 39:
2858 return "CS2";
2859 break;
2860 case 40:
2861 return "COS";
2862 break;
2863 case 41:
2864 return "CD4";
2865 break;
2866 case 42:
2867 return "BF3";
2868 break;
2869 case 43:
2870 return "C2H2F4";
2871 break;
2872 case 44:
2873 return version <= 11 ? "He-3" : "TMA";
2874 break;
2875 case 45:
2876 return version <= 11 ? "He" : "paraH2";
2877 break;
2878 case 46:
2879 return version <= 11 ? "Ne" : "nC3H7OH";
2880 break;
2881 case 47:
2882 return "Ar";
2883 break;
2884 case 48:
2885 return version <= 11 ? "Kr" : "orthoD2";
2886 break;
2887 case 49:
2888 return "Xe";
2889 break;
2890 case 50:
2891 return "CHF3";
2892 break;
2893 case 51:
2894 return "CF3Br";
2895 break;
2896 case 52:
2897 return "C3F8";
2898 break;
2899 case 53:
2900 return "O3";
2901 break;
2902 case 54:
2903 return "Hg";
2904 break;
2905 case 55:
2906 return "H2S";
2907 break;
2908 case 56:
2909 return "nC4H10";
2910 break;
2911 case 57:
2912 return "nC5H12";
2913 break;
2914 case 58:
2915 return "N2";
2916 break;
2917 case 59:
2918 return "GeH4";
2919 break;
2920 case 60:
2921 return "SiH4";
2922 break;
2923 default:
2924 return "";
2925 break;
2926 }
2927 return "";
2928}

Referenced by DisablePenningTransfer(), Garfield::MediumMagboltz::DisablePenningTransfer(), EnablePenningTransfer(), Garfield::MediumMagboltz::EnablePenningTransfer(), GetMixture(), SetComposition(), and Garfield::MediumMagboltz::SetExcitationScaling().

◆ GetGasName() [2/2]

std::string Garfield::MediumGas::GetGasName ( std::string  input) const
protected

Definition at line 2930 of file MediumGas.cc.

2930 {
2931 // Convert to upper-case
2932 for (unsigned int i = 0; i < input.length(); ++i) {
2933 input[i] = toupper(input[i]);
2934 }
2935
2936 if (input.empty()) return "";
2937
2938 if (input == "CF4" || input == "FREON" || input == "FREON-14" ||
2939 input == "TETRAFLUOROMETHANE") {
2940 return "CF4";
2941 } else if (input == "AR" || input == "ARGON") {
2942 return "Ar";
2943 } else if (input == "HE" || input == "HELIUM" || input == "HE-4" ||
2944 input == "HE 4" || input == "HE4" || input == "4-HE" ||
2945 input == "4 HE" || input == "4HE" || input == "HELIUM-4" ||
2946 input == "HELIUM 4" || input == "HELIUM4") {
2947 return "He";
2948 } else if (input == "HE-3" || input == "HE3" || input == "HELIUM-3" ||
2949 input == "HELIUM 3" || input == "HELIUM3") {
2950 return "He-3";
2951 } else if (input == "NE" || input == "NEON") {
2952 return "Ne";
2953 } else if (input == "KR" || input == "KRYPTON") {
2954 return "Kr";
2955 } else if (input == "XE" || input == "XENON") {
2956 return "Xe";
2957 } else if (input == "CH4" || input == "METHANE") {
2958 return "CH4";
2959 } else if (input == "C2H6" || input == "ETHANE") {
2960 return "C2H6";
2961 } else if (input == "C3H8" || input == "PROPANE") {
2962 return "C3H8";
2963 } else if (input == "C4H10" || input == "ISOBUTANE" || input == "ISO" ||
2964 input == "IC4H10" || input == "ISO-C4H10" || input == "ISOC4H10") {
2965 return "iC4H10";
2966 } else if (input == "CO2" || input == "CARBON-DIOXIDE" ||
2967 input == "CARBON DIOXIDE" || input == "CARBONDIOXIDE") {
2968 return "CO2";
2969 } else if (input == "NEOPENTANE" || input == "NEO-PENTANE" ||
2970 input == "NEO-C5H12" || input == "NEOC5H12" ||
2971 input == "DIMETHYLPROPANE" || input == "C5H12") {
2972 return "neoC5H12";
2973 } else if (input == "H2O" || input == "WATER" || input == "WATER-VAPOUR" ||
2974 input == "WATER VAPOUR") {
2975 return "H2O";
2976 } else if (input == "O2" || input == "OXYGEN") {
2977 return "O2";
2978 } else if (input == "NI" || input == "NITRO" || input == "N2" ||
2979 input == "NITROGEN") {
2980 return "N2";
2981 } else if (input == "NO" || input == "NITRIC-OXIDE" || input == "NITRIC OXIDE" ||
2982 input == "NITROGEN-MONOXIDE" || input == "NITROGEN MONOXIDE") {
2983 return "NO";
2984 } else if (input == "N2O" || input == "NITROUS-OXIDE" || input == "NITROUS OXIDE" ||
2985 input == "DINITROGEN-MONOXIDE" || input == "LAUGHING-GAS") {
2986 return "N2O";
2987 } else if (input == "C2H4" || input == "ETHENE" || input == "ETHYLENE") {
2988 return "C2H4";
2989 } else if (input == "C2H2" || input == "ACETYL" || input == "ACETYLENE" ||
2990 input == "ETHYNE") {
2991 return "C2H2";
2992 } else if (input == "H2" || input == "HYDROGEN") {
2993 return "H2";
2994 } else if (input == "PARA H2" || input == "PARA-H2" ||
2995 input == "PARAH2" || input == "PARA HYDROGEN" ||
2996 input == "PARA-HYDROGEN" || input == "PARAHYDROGEN") {
2997 return "paraH2";
2998 } else if (input == "D2" || input == "DEUTERIUM") {
2999 return "D2";
3000 } else if (input == "ORTHO D2" || input == "ORTHO-D2" ||
3001 input == "ORTHOD2" || input == "ORTHO DEUTERIUM" ||
3002 input == "ORTHO-DEUTERIUM" || input == "ORTHODEUTERIUM") {
3003 return "orthoD2";
3004 } else if (input == "CO" || input == "CARBON-MONOXIDE" ||
3005 input == "CARBON MONOXIDE") {
3006 return "CO";
3007 } else if (input == "METHYLAL" || input == "METHYLAL-HOT" || input == "DMM" ||
3008 input == "DIMETHOXYMETHANE" || input == "FORMAL" || input == "C3H8O2") {
3009 // Methylal (dimethoxymethane, CH3-O-CH2-O-CH3, "hot" version)
3010 return "Methylal";
3011 } else if (input == "DME" || input == "DIMETHYL-ETHER" || input == "DIMETHYLETHER" ||
3012 input == "DIMETHYL ETHER" || input == "METHYL ETHER" ||
3013 input == "METHYL-ETHER" || input == "METHYLETHER" ||
3014 input == "WOOD-ETHER" || input == "WOODETHER" || input == "WOOD ETHER" ||
3015 input == "DIMETHYL OXIDE" || input == "DIMETHYL-OXIDE" ||
3016 input == "DEMEON" || input == "METHOXYMETHANE" || input == "C4H10O2") {
3017 return "DME";
3018 } else if (input == "REID-STEP") {
3019 return "Reid-Step";
3020 } else if (input == "MAXWELL-MODEL") {
3021 return "Maxwell-Model";
3022 } else if (input == "REID-RAMP") {
3023 return "Reid-Ramp";
3024 } else if (input == "C2F6" || input == "FREON-116" || input == "ZYRON-116" ||
3025 input == "ZYRON-116-N5" || input == "HEXAFLUOROETHANE") {
3026 return "C2F6";
3027 } else if (input == "SF6" || input == "SULPHUR-HEXAFLUORIDE" ||
3028 input == "SULFUR-HEXAFLUORIDE" || input == "SULPHUR HEXAFLUORIDE" ||
3029 input == "SULFUR HEXAFLUORIDE") {
3030 return "SF6";
3031 } else if (input == "NH3" || input == "AMMONIA") {
3032 return "NH3";
3033 } else if (input == "C3H6" || input == "PROPENE" || input == "PROPYLENE") {
3034 return "C3H6";
3035 } else if (input == "C-PROPANE" || input == "CYCLO-PROPANE" ||
3036 input == "CYCLO PROPANE" || input == "CYCLOPROPANE" ||
3037 input == "C-C3H6" || input == "CC3H6" || input == "CYCLO-C3H6") {
3038 return "cC3H6";
3039 } else if (input == "METHANOL" || input == "METHYL-ALCOHOL" ||
3040 input == "METHYL ALCOHOL" || input == "WOOD ALCOHOL" ||
3041 input == "WOOD-ALCOHOL" || input == "CH3OH") {
3042 return "CH3OH";
3043 } else if (input == "ETHANOL" || input == "ETHYL-ALCOHOL" ||
3044 input == "ETHYL ALCOHOL" || input == "GRAIN ALCOHOL" ||
3045 input == "GRAIN-ALCOHOL" || input == "C2H5OH") {
3046 return "C2H5OH";
3047 } else if (input == "PROPANOL" || input == "2-PROPANOL" || input == "ISOPROPYL" ||
3048 input == "ISO-PROPANOL" || input == "ISOPROPANOL" ||
3049 input == "ISOPROPYL ALCOHOL" || input == "ISOPROPYL-ALCOHOL" ||
3050 input == "C3H7OH") {
3051 return "C3H7OH";
3052 } else if (input == "NPROPANOL" || input == "N-PROPANOL" ||
3053 input == "1-PROPANOL" || input == "PROPYL ALCOHOL" ||
3054 input == "PROPYL-ALCOHOL" || input == "N-PROPYL ALCOHOL" ||
3055 input == "NC3H7OH" || input == "N-C3H7OH") {
3056 return "nC3H7OH";
3057 } else if (input == "CS" || input == "CESIUM" || input == "CAESIUM") {
3058 return "Cs";
3059 } else if (input == "F2" || input == "FLUOR" || input == "FLUORINE") {
3060 return "F2";
3061 } else if (input == "CS2" || input == "CARBON-DISULPHIDE" ||
3062 input == "CARBON-DISULFIDE" || input == "CARBON DISULPHIDE" ||
3063 input == "CARBON DISULFIDE") {
3064 return "CS2";
3065 } else if (input == "COS" || input == "CARBONYL-SULPHIDE" ||
3066 input == "CARBONYL-SULFIDE" || input == "CARBONYL SULFIDE") {
3067 return "COS";
3068 } else if (input == "DEUT-METHANE" || input == "DEUTERIUM-METHANE" ||
3069 input == "DEUTERATED-METHANE" || input == "DEUTERATED METHANE" ||
3070 input == "DEUTERIUM METHANE" || input == "CD4") {
3071 return "CD4";
3072 } else if (input == "BF3" || input == "BORON-TRIFLUORIDE" ||
3073 input == "BORON TRIFLUORIDE") {
3074 return "BF3";
3075 } else if (input == "C2HF5" || input == "C2H2F4" || input == "C2F5H" ||
3076 input == "C2F4H2" || input == "FREON 134" || input == "FREON 134A" ||
3077 input == "FREON-134" || input == "FREON-134-A" || input == "FREON 125" ||
3078 input == "ZYRON 125" || input == "FREON-125" || input == "ZYRON-125" ||
3079 input == "TETRAFLUOROETHANE" || input == "PENTAFLUOROETHANE") {
3080 // C2H2F4 (and C2HF5).
3081 return "C2H2F4";
3082 } else if (input == "TMA" || input == "TRIMETHYLAMINE" || input == "N(CH3)3" ||
3083 input == "N-(CH3)3") {
3084 return "TMA";
3085 } else if (input == "CHF3" || input == "FREON-23" || input == "TRIFLUOROMETHANE" ||
3086 input == "FLUOROFORM") {
3087 return "CHF3";
3088 } else if (input == "CF3BR" || input == "TRIFLUOROBROMOMETHANE" ||
3089 input == "BROMOTRIFLUOROMETHANE" || input == "HALON-1301" ||
3090 input == "HALON 1301" || input == "FREON-13B1" || input == "FREON 13BI") {
3091 return "CF3Br";
3092 } else if (input == "C3F8" || input == "OCTAFLUOROPROPANE" || input == "R218" ||
3093 input == "R-218" || input == "FREON 218" || input == "FREON-218" ||
3094 input == "PERFLUOROPROPANE" || input == "RC 218" || input == "PFC 218" ||
3095 input == "RC-218" || input == "PFC-218" || input == "FLUTEC PP30" ||
3096 input == "GENETRON 218") {
3097 return "C3F8";
3098 } else if (input == "OZONE" || input == "O3") {
3099 return "O3";
3100 } else if (input == "MERCURY" || input == "HG" || input == "HG2") {
3101 return "Hg";
3102 } else if (input == "H2S" || input == "HYDROGEN SULPHIDE" || input == "SEWER GAS" ||
3103 input == "HYDROGEN-SULPHIDE" || input == "SEWER-GAS" ||
3104 input == "HYDROGEN SULFIDE" || input == "HEPATIC ACID" ||
3105 input == "HYDROGEN-SULFIDE" || input == "HEPATIC-ACID" ||
3106 input == "SULFUR HYDRIDE" || input == "DIHYDROGEN MONOSULFIDE" ||
3107 input == "SULFUR-HYDRIDE" || input == "DIHYDROGEN-MONOSULFIDE" ||
3108 input == "DIHYDROGEN MONOSULPHIDE" || input == "SULPHUR HYDRIDE" ||
3109 input == "DIHYDROGEN-MONOSULPHIDE" || input == "SULPHUR-HYDRIDE" ||
3110 input == "STINK DAMP" || input == "SULFURATED HYDROGEN" ||
3111 input == "STINK-DAMP" || input == "SULFURATED-HYDROGEN") {
3112 return "H2S";
3113 } else if (input == "N-BUTANE" || input == "N-C4H10" || input == "NBUTANE" ||
3114 input == "NC4H10") {
3115 return "nC4H10";
3116 } else if (input == "N-PENTANE" || input == "N-C5H12" || input == "NPENTANE" ||
3117 input == "NC5H12") {
3118 return "nC5H12";
3119 } else if (input == "NI-PHELPS" || input == "NI PHELPS" ||
3120 input == "NITROGEN-PHELPS" || input == "NITROGEN PHELPHS" ||
3121 input == "N2-PHELPS" || input == "N2 PHELPS" || input == "N2 (PHELPS)") {
3122 // Nitrogen
3123 return "N2 (Phelps)";
3124 } else if (input == "GERMANE" || input == "GERM" || input == "GERMANIUM-HYDRIDE" ||
3125 input == "GERMANIUM HYDRIDE" || input == "GERMANIUM TETRAHYDRIDE" ||
3126 input == "GERMANIUM-TETRAHYDRIDE" || input == "GERMANOMETHANE" ||
3127 input == "MONOGERMANE" || input == "GEH4") {
3128 return "GeH4";
3129 } else if (input == "SILANE" || input == "SIL" || input == "SILICON-HYDRIDE" ||
3130 input == "SILICON HYDRIDE" || input == "SILICON-TETRAHYDRIDE" ||
3131 input == "SILICANE" || input == "MONOSILANE" || input == "SIH4") {
3132 return "SiH4";
3133 }
3134
3135 std::cerr << m_className << "::GetGasName:\n"
3136 << " Gas " << input << " is not recognized.\n";
3137 return "";
3138}

◆ GetGasNumberGasFile()

int Garfield::MediumGas::GetGasNumberGasFile ( const std::string &  input) const
protected

Definition at line 3140 of file MediumGas.cc.

3140 {
3141
3142 if (input.empty()) return 0;
3143
3144 if (input == "CF4") {
3145 return 1;
3146 } else if (input == "Ar") {
3147 return 2;
3148 } else if (input == "He" || input == "He-4") {
3149 return 3;
3150 } else if (input == "He-3") {
3151 return 4;
3152 } else if (input == "Ne") {
3153 return 5;
3154 } else if (input == "Kr") {
3155 return 6;
3156 } else if (input == "Xe") {
3157 return 7;
3158 } else if (input == "CH4") {
3159 // Methane
3160 return 8;
3161 } else if (input == "C2H6") {
3162 // Ethane
3163 return 9;
3164 } else if (input == "C3H8") {
3165 // Propane
3166 return 10;
3167 } else if (input == "iC4H10") {
3168 // Isobutane
3169 return 11;
3170 } else if (input == "CO2") {
3171 return 12;
3172 } else if (input == "neoC5H12") {
3173 // Neopentane
3174 return 13;
3175 } else if (input == "H2O") {
3176 return 14;
3177 } else if (input == "O2") {
3178 return 15;
3179 } else if (input == "N2") {
3180 return 16;
3181 } else if (input == "NO") {
3182 // Nitric oxide
3183 return 17;
3184 } else if (input == "N2O") {
3185 // Nitrous oxide
3186 return 18;
3187 } else if (input == "C2H4") {
3188 // Ethene
3189 return 19;
3190 } else if (input == "C2H2") {
3191 // Acetylene
3192 return 20;
3193 } else if (input == "H2") {
3194 return 21;
3195 } else if (input == "D2") {
3196 // Deuterium
3197 return 22;
3198 } else if (input == "CO") {
3199 return 23;
3200 } else if (input == "Methylal") {
3201 // Methylal (dimethoxymethane, CH3-O-CH2-O-CH3, "hot" version)
3202 return 24;
3203 } else if (input == "DME") {
3204 return 25;
3205 } else if (input == "Reid-Step") {
3206 return 26;
3207 } else if (input == "Maxwell-Model") {
3208 return 27;
3209 } else if (input == "Reid-Ramp") {
3210 return 28;
3211 } else if (input == "C2F6") {
3212 return 29;
3213 } else if (input == "SF6") {
3214 return 30;
3215 } else if (input == "NH3") {
3216 return 31;
3217 } else if (input == "C3H6") {
3218 // Propene
3219 return 32;
3220 } else if (input == "cC3H6") {
3221 // Cyclopropane
3222 return 33;
3223 } else if (input == "CH3OH") {
3224 // Methanol
3225 return 34;
3226 } else if (input == "C2H5OH") {
3227 // Ethanol
3228 return 35;
3229 } else if (input == "C3H7OH") {
3230 // Propanol
3231 return 36;
3232 } else if (input == "Cs") {
3233 return 37;
3234 } else if (input == "F2") {
3235 // Fluorine
3236 return 38;
3237 } else if (input == "CS2") {
3238 return 39;
3239 } else if (input == "COS") {
3240 return 40;
3241 } else if (input == "CD4") {
3242 // Deuterated methane
3243 return 41;
3244 } else if (input == "BF3") {
3245 return 42;
3246 } else if (input == "C2HF5" || input == "C2H2F4") {
3247 return 43;
3248 } else if (input == "TMA") {
3249 return 44;
3250 } else if (input == "paraH2") {
3251 return 45;
3252 } else if (input == "nC3H7OH") {
3253 return 46;
3254 } else if (input == "orthoD2") {
3255 return 48;
3256 } else if (input == "CHF3") {
3257 return 50;
3258 } else if (input == "CF3Br") {
3259 return 51;
3260 } else if (input == "C3F8") {
3261 return 52;
3262 } else if (input == "O3") {
3263 // Ozone
3264 return 53;
3265 } else if (input == "Hg") {
3266 return 54;
3267 } else if (input == "H2S") {
3268 return 55;
3269 } else if (input == "nC4H10") {
3270 // n-butane
3271 return 56;
3272 } else if (input == "nC5H12") {
3273 // n-pentane
3274 return 57;
3275 } else if (input == "N2 (Phelps)") {
3276 return 58;
3277 } else if (input == "GeH4") {
3278 // Germane
3279 return 59;
3280 } else if (input == "SiH4") {
3281 // Silane
3282 return 60;
3283 }
3284
3285 std::cerr << m_className << "::GetGasNumberGasFile:\n"
3286 << " Gas " << input << " not found.\n";
3287 return 0;
3288}

Referenced by WriteGasFile().

◆ GetMassDensity()

double Garfield::MediumGas::GetMassDensity ( ) const
overridevirtual

Get the mass density [g/cm3].

Reimplemented from Garfield::Medium.

Definition at line 298 of file MediumGas.cc.

298 {
299 return GetNumberDensity() * GetAtomicWeight() * AtomicMassUnit;
300}
double GetNumberDensity() const override
Get the number density [cm-3].
Definition: MediumGas.cc:292
double GetAtomicWeight() const override
Get the effective atomic weight.
Definition: MediumGas.cc:283

◆ GetMixture()

bool Garfield::MediumGas::GetMixture ( const std::vector< double > &  mixture,
const int  version,
std::vector< std::string > &  gasnames,
std::vector< double > &  percentages 
) const
protected

Definition at line 907 of file MediumGas.cc.

909 {
910
911 gasnames.clear();
912 percentages.clear();
913 const unsigned int nMagboltzGases = mixture.size();
914 for (unsigned int i = 0; i < nMagboltzGases; ++i) {
915 if (mixture[i] < Small) continue;
916 const std::string gasname = GetGasName(i + 1, version);
917 if (gasname.empty()) {
918 std::cerr << m_className << "::GetMixture:\n"
919 << " Unknown gas (gas number " << i + 1 << ").\n";
920 return false;
921 }
922 gasnames.push_back(gasname);
923 percentages.push_back(mixture[i]);
924 }
925 if (gasnames.size() > m_nMaxGases) {
926 std::cerr << m_className << "::GetMixture:\n"
927 << " Gas mixture has " << gasnames.size() << " components.\n"
928 << " Number of gases is limited to " << m_nMaxGases << ".\n";
929 return false;
930 } else if (gasnames.empty()) {
931 std::cerr << m_className << "::GetMixture:\n"
932 << " Gas mixture is not defined (zero components).\n";
933 return false;
934 }
935 double sum = std::accumulate(percentages.begin(), percentages.end(), 0.);
936 if (sum != 100.) {
937 std::cout << m_className << "::GetMixture:\n"
938 << " Renormalizing the percentages.\n";
939 for (auto& percentage : percentages) percentage *= 100. / sum;
940 }
941 return true;
942}
static constexpr unsigned int m_nMaxGases
Definition: MediumGas.hh:126

Referenced by LoadGasFile(), and MergeGasFile().

◆ GetNumberDensity()

double Garfield::MediumGas::GetNumberDensity ( ) const
overridevirtual

Get the number density [cm-3].

Reimplemented from Garfield::Medium.

Definition at line 292 of file MediumGas.cc.

292 {
293 // Ideal gas law.
294 return LoschmidtNumber * (m_pressure / AtmosphericPressure) *
295 (ZeroCelsius / m_temperature);
296}

Referenced by GetMassDensity(), and LoadIonMobility().

◆ GetPhotoAbsorptionCrossSection()

bool Garfield::MediumGas::GetPhotoAbsorptionCrossSection ( const double  e,
double &  sigma,
const unsigned int  i 
)
overridevirtual

Reimplemented from Garfield::Medium.

Definition at line 3290 of file MediumGas.cc.

3291 {
3292 if (i >= m_nMaxGases) {
3293 std::cerr << m_className
3294 << "::GetPhotoAbsorptionCrossSection: Index out of range.\n";
3295 return false;
3296 }
3297
3298 OpticalData optData;
3299 if (!optData.IsAvailable(m_gas[i])) return false;
3300 double eta = 0.;
3301 return optData.GetPhotoabsorptionCrossSection(m_gas[i], e, sigma, eta);
3302}

◆ InsertA()

void Garfield::MediumGas::InsertA ( const int  ia,
const int  ne,
const int  nb,
const int  na 
)
protected

Definition at line 1689 of file MediumGas.cc.

1690 {
1691 ResizeA(m_eVelE, ne, nb, na + 1);
1692 ResizeA(m_eVelB, ne, nb, na + 1);
1693 ResizeA(m_eVelX, ne, nb, na + 1);
1694 ResizeA(m_eDifL, ne, nb, na + 1);
1695 ResizeA(m_eDifT, ne, nb, na + 1);
1696 ResizeA(m_eAlp, ne, nb, na + 1);
1697 ResizeA(m_eAlp0, ne, nb, na + 1);
1698 ResizeA(m_eAtt, ne, nb, na + 1);
1699 ResizeA(m_eLor, ne, nb, na + 1);
1700 ResizeA(m_iMob, ne, nb, na + 1);
1701 ResizeA(m_iDis, ne, nb, na + 1);
1702 ResizeA(m_iDifL, ne, nb, na + 1);
1703 ResizeA(m_iDifT, ne, nb, na + 1);
1704 for (auto& dif : m_eDifM) ResizeA(dif, ne, nb, na + 1);
1705 for (auto& exc : m_excRates) ResizeA(exc, ne, nb, na + 1);
1706 for (auto& ion : m_ionRates) ResizeA(ion, ne, nb, na + 1);
1707 for (int j = 0; j < nb; ++j) {
1708 for (int i = 0; i < ne; ++i) {
1709 for (int k = na; k > ia; k--) {
1710 if (!m_eVelE.empty()) m_eVelE[k][j][i] = m_eVelE[k - 1][j][i];
1711 if (!m_eVelB.empty()) m_eVelB[k][j][i] = m_eVelB[k - 1][j][i];
1712 if (!m_eVelX.empty()) m_eVelX[k][j][i] = m_eVelX[k - 1][j][i];
1713 if (!m_eDifL.empty()) m_eDifL[k][j][i] = m_eDifL[k - 1][j][i];
1714 if (!m_eDifT.empty()) m_eDifT[k][j][i] = m_eDifT[k - 1][j][i];
1715 if (!m_eAlp.empty()) m_eAlp[k][j][i] = m_eAlp[k - 1][j][i];
1716 if (!m_eAlp0.empty()) m_eAlp0[k][j][i] = m_eAlp0[k - 1][j][i];
1717 if (!m_eAtt.empty()) m_eAtt[k][j][i] = m_eAtt[k - 1][j][i];
1718 if (!m_eLor.empty()) m_eLor[k][j][i] = m_eLor[k - 1][j][i];
1719 if (!m_iMob.empty()) m_iMob[k][j][i] = m_iMob[k - 1][j][i];
1720 if (!m_iDis.empty()) m_iDis[k][j][i] = m_iDis[k - 1][j][i];
1721 if (!m_iDifL.empty()) m_iDifL[k][j][i] = m_iDifL[k - 1][j][i];
1722 if (!m_iDifT.empty()) m_iDifT[k][j][i] = m_iDifT[k - 1][j][i];
1723 for (auto& dif : m_eDifM) dif[k][j][i] = dif[k - 1][j][i];
1724 for (auto& exc : m_excRates) exc[k][j][i] = exc[k - 1][j][i];
1725 for (auto& ion : m_ionRates) ion[k][j][i] = ion[k - 1][j][i];
1726 }
1727 }
1728 }
1729}
std::vector< std::vector< std::vector< double > > > m_iDifT
Definition: Medium.hh:578
std::vector< std::vector< std::vector< double > > > m_iDifL
Definition: Medium.hh:577

Referenced by MergeGasFile().

◆ InsertB()

void Garfield::MediumGas::InsertB ( const int  ib,
const int  ne,
const int  nb,
const int  na 
)
protected

Definition at line 1641 of file MediumGas.cc.

1642 {
1643 for (int k = 0; k < na; ++k) {
1644 if (!m_eVelE.empty()) m_eVelE[k].resize(nb + 1, std::vector<double>(ne, 0.));
1645 if (!m_eVelB.empty()) m_eVelB[k].resize(nb + 1, std::vector<double>(ne, 0.));
1646 if (!m_eVelX.empty()) m_eVelX[k].resize(nb + 1, std::vector<double>(ne, 0.));
1647 if (!m_eDifL.empty()) m_eDifL[k].resize(nb + 1, std::vector<double>(ne, 0.));
1648 if (!m_eDifT.empty()) m_eDifT[k].resize(nb + 1, std::vector<double>(ne, 0.));
1649 if (!m_eAlp.empty()) m_eAlp[k].resize(nb + 1, std::vector<double>(ne, 0.));
1650 if (!m_eAlp0.empty()) m_eAlp0[k].resize(nb + 1, std::vector<double>(ne, 0.));
1651 if (!m_eAtt.empty()) m_eAtt[k].resize(nb + 1, std::vector<double>(ne, 0.));
1652 if (!m_eLor.empty()) m_eLor[k].resize(nb + 1, std::vector<double>(ne, 0.));
1653 if (!m_iMob.empty()) m_iMob[k].resize(nb + 1, std::vector<double>(ne, 0.));
1654 if (!m_iDis.empty()) m_iDis[k].resize(nb + 1, std::vector<double>(ne, 0.));
1655 if (!m_iDifL.empty()) m_iDifL[k].resize(nb + 1, std::vector<double>(ne, 0.));
1656 if (!m_iDifT.empty()) m_iDifT[k].resize(nb + 1, std::vector<double>(ne, 0.));
1657 for (auto& dif : m_eDifM) {
1658 dif[k].resize(nb + 1, std::vector<double>(ne, 0.));
1659 }
1660 for (auto& exc : m_excRates) {
1661 exc[k].resize(nb + 1, std::vector<double>(ne, 0.));
1662 }
1663 for (auto& ion : m_ionRates) {
1664 ion[k].resize(nb + 1, std::vector<double>(ne, 0.));
1665 }
1666 for (int i = 0; i < ne; ++i) {
1667 for (int j = nb; j > ib; j--) {
1668 if (!m_eVelE.empty()) m_eVelE[k][j][i] = m_eVelE[k][j - 1][i];
1669 if (!m_eVelB.empty()) m_eVelB[k][j][i] = m_eVelB[k][j - 1][i];
1670 if (!m_eVelX.empty()) m_eVelX[k][j][i] = m_eVelX[k][j - 1][i];
1671 if (!m_eDifL.empty()) m_eDifL[k][j][i] = m_eDifL[k][j - 1][i];
1672 if (!m_eDifT.empty()) m_eDifT[k][j][i] = m_eDifT[k][j - 1][i];
1673 if (!m_eAlp.empty()) m_eAlp[k][j][i] = m_eAlp[k][j - 1][i];
1674 if (!m_eAlp0.empty()) m_eAlp0[k][j][i] = m_eAlp0[k][j - 1][i];
1675 if (!m_eAtt.empty()) m_eAtt[k][j][i] = m_eAtt[k][j - 1][i];
1676 if (!m_eLor.empty()) m_eLor[k][j][i] = m_eLor[k][j - 1][i];
1677 if (!m_iMob.empty()) m_iMob[k][j][i] = m_iMob[k][j - 1][i];
1678 if (!m_iDis.empty()) m_iDis[k][j][i] = m_iDis[k][j - 1][i];
1679 if (!m_iDifL.empty()) m_iDifL[k][j][i] = m_iDifL[k][j - 1][i];
1680 if (!m_iDifT.empty()) m_iDifT[k][j][i] = m_iDifT[k][j - 1][i];
1681 for (auto& dif : m_eDifM) dif[k][j][i] = dif[k][j - 1][i];
1682 for (auto& exc : m_excRates) exc[k][j][i] = exc[k][j - 1][i];
1683 for (auto& ion : m_ionRates) ion[k][j][i] = ion[k][j - 1][i];
1684 }
1685 }
1686 }
1687}

Referenced by MergeGasFile().

◆ InsertE()

void Garfield::MediumGas::InsertE ( const int  ie,
const int  ne,
const int  nb,
const int  na 
)
protected

Definition at line 1599 of file MediumGas.cc.

1600 {
1601 for (int k = 0; k < na; ++k) {
1602 for (int j = 0; j < nb; ++j) {
1603 if (!m_eVelE.empty()) m_eVelE[k][j].resize(ne + 1, 0.);
1604 if (!m_eVelB.empty()) m_eVelB[k][j].resize(ne + 1, 0.);
1605 if (!m_eVelX.empty()) m_eVelX[k][j].resize(ne + 1, 0.);
1606 if (!m_eDifL.empty()) m_eDifL[k][j].resize(ne + 1, 0.);
1607 if (!m_eDifT.empty()) m_eDifT[k][j].resize(ne + 1, 0.);
1608 if (!m_eAlp.empty()) m_eAlp[k][j].resize(ne + 1, 0.);
1609 if (!m_eAlp0.empty()) m_eAlp0[k][j].resize(ne + 1, 0.);
1610 if (!m_eAtt.empty()) m_eAtt[k][j].resize(ne + 1, 0.);
1611 if (!m_eLor.empty()) m_eLor[k][j].resize(ne + 1, 0.);
1612 if (!m_iMob.empty()) m_iMob[k][j].resize(ne + 1, 0.);
1613 if (!m_iDis.empty()) m_iDis[k][j].resize(ne + 1, 0.);
1614 if (!m_iDifL.empty()) m_iDifL[k][j].resize(ne + 1, 0.);
1615 if (!m_iDifT.empty()) m_iDifT[k][j].resize(ne + 1, 0.);
1616 for (auto& dif : m_eDifM) dif[k][j].resize(ne + 1, 0.);
1617 for (auto& exc : m_excRates) exc[k][j].resize(ne + 1, 0.);
1618 for (auto& ion : m_ionRates) ion[k][j].resize(ne + 1, 0.);
1619 for (int i = ne; i > ie; --i) {
1620 if (!m_eVelE.empty()) m_eVelE[k][j][i] = m_eVelE[k][j][i - 1];
1621 if (!m_eVelB.empty()) m_eVelB[k][j][i] = m_eVelB[k][j][i - 1];
1622 if (!m_eVelX.empty()) m_eVelX[k][j][i] = m_eVelX[k][j][i - 1];
1623 if (!m_eDifL.empty()) m_eDifL[k][j][i] = m_eDifL[k][j][i - 1];
1624 if (!m_eDifT.empty()) m_eDifT[k][j][i] = m_eDifT[k][j][i - 1];
1625 if (!m_eAlp.empty()) m_eAlp[k][j][i] = m_eAlp[k][j][i - 1];
1626 if (!m_eAlp0.empty()) m_eAlp0[k][j][i] = m_eAlp0[k][j][i - 1];
1627 if (!m_eAtt.empty()) m_eAtt[k][j][i] = m_eAtt[k][j][i - 1];
1628 if (!m_eLor.empty()) m_eLor[k][j][i] = m_eLor[k][j][i - 1];
1629 if (!m_iMob.empty()) m_iMob[k][j][i] = m_iMob[k][j][i - 1];
1630 if (!m_iDis.empty()) m_iDis[k][j][i] = m_iDis[k][j][i - 1];
1631 if (!m_iDifL.empty()) m_iDifL[k][j][i] = m_iDifL[k][j][i - 1];
1632 if (!m_iDifT.empty()) m_iDifT[k][j][i] = m_iDifT[k][j][i - 1];
1633 for (auto& dif : m_eDifM) dif[k][j][i] = dif[k][j][i - 1];
1634 for (auto& exc : m_excRates) exc[k][j][i] = exc[k][j][i - 1];
1635 for (auto& ion : m_ionRates) ion[k][j][i] = ion[k][j][i - 1];
1636 }
1637 }
1638 }
1639}

Referenced by MergeGasFile().

◆ IsGas()

bool Garfield::MediumGas::IsGas ( ) const
inlineoverridevirtual

Is this medium a gas?

Reimplemented from Garfield::Medium.

Definition at line 22 of file MediumGas.hh.

22{ return true; }

◆ LoadGasFile()

bool Garfield::MediumGas::LoadGasFile ( const std::string &  filename)

Read table of gas properties (transport parameters) from file.

Definition at line 311 of file MediumGas.cc.

311 {
312
313 // -----------------------------------------------------------------------
314 // GASGET
315 // -----------------------------------------------------------------------
316
317 std::ifstream gasfile;
318 // Open the file.
319 gasfile.open(filename.c_str());
320 // Make sure the file could be opened.
321 if (!gasfile.is_open()) {
322 std::cerr << m_className << "::LoadGasFile:\n"
323 << " Cannot open file " << filename << ".\n";
324 return false;
325 }
326 std::cout << m_className << "::LoadGasFile: Reading " << filename << ".\n";
327
328 ResetTables();
329
330 // Start reading the data.
331 if (m_debug) std::cout << m_className << "::LoadGasFile: Reading header.\n";
332 int version = 12;
333 // GASOK bits
334 std::bitset<20> gasok;
335 // Gas composition
336 constexpr int nMagboltzGases = 60;
337 std::vector<double> mixture(nMagboltzGases, 0.);
338 if (!ReadHeader(gasfile, version, gasok, m_tab2d, mixture,
340 gasfile.close();
341 return false;
342 }
343 std::cout << m_className << "::LoadGasFile: Version " << version << "\n";
344
345 // Check the gas mixture.
346 std::vector<std::string> gasnames;
347 std::vector<double> percentages;
348 if (!GetMixture(mixture, version, gasnames, percentages)) {
349 std::cerr << m_className << "::LoadGasFile:\n "
350 << "Cannot determine the gas composition.\n";
351 gasfile.close();
352 return false;
353 }
354
355 m_name = "";
356 m_nComponents = gasnames.size();
357 for (unsigned int i = 0; i < m_nComponents; ++i) {
358 if (i > 0) m_name += "/";
359 m_name += gasnames[i];
360 m_gas[i] = gasnames[i];
361 m_fraction[i] = percentages[i] / 100.;
363 }
364 std::cout << m_className << "::LoadGasFile:\n"
365 << " Gas composition set to " << m_name;
366 if (m_nComponents > 1) {
367 std::cout << " (" << m_fraction[0] * 100;
368 for (unsigned int i = 1; i < m_nComponents; ++i) {
369 std::cout << "/" << m_fraction[i] * 100;
370 }
371 std::cout << ")";
372 }
373 std::cout << "\n";
374
375 const int nE = m_eFields.size();
376 const int nB = m_bFields.size();
377 const int nA = m_bAngles.size();
378 if (m_debug) {
379 std::cout << m_className << "::LoadGasFile:\n " << nE
380 << " electric field(s), " << nB
381 << " magnetic field(s), " << nA << " angle(s).\n";
382 }
383
384 // Decode the GASOK bits.
385 // GASOK(I) : .TRUE. if present
386 // (1) electron drift velocity || E
387 // (2) ion mobility,
388 // (3) longitudinal diffusion || E
389 // (4) Townsend coefficient,
390 // (5) cluster size distribution.
391 // (6) attachment coefficient,
392 // (7) Lorentz angle,
393 // (8) transverse diffusion || ExB and Bt
394 // (9) electron drift velocity || Bt
395 // (10) electron drift velocity || ExB
396 // (11) diffusion tensor
397 // (12) ion dissociation
398 // (13) allocated for SRIM data (not used)
399 // (14) allocated for HEED data (not used)
400 // (15) excitation rates
401 // (16) ionisation rates
402
403 if (gasok[0]) Init(nE, nB, nA, m_eVelE, 0.);
404 if (gasok[1]) Init(nE, nB, nA, m_iMob, 0.);
405 if (gasok[2]) Init(nE, nB, nA, m_eDifL, 0.);
406 if (gasok[3]) {
407 Init(nE, nB, nA, m_eAlp, -30.);
408 Init(nE, nB, nA, m_eAlp0, -30.);
409 }
410 if (gasok[5]) Init(nE, nB, nA, m_eAtt, -30.);
411 if (gasok[6]) Init(nE, nB, nA, m_eLor, -30.);
412 if (gasok[7]) Init(nE, nB, nA, m_eDifT, 0.);
413 if (gasok[8]) Init(nE, nB, nA, m_eVelB, 0.);
414 if (gasok[9]) Init(nE, nB, nA, m_eVelX, 0.);
415 if (gasok[10]) Init(nE, nB, nA, 6, m_eDifM, 0.);
416 if (gasok[11]) Init(nE, nB, nA, m_iDis, -30.);
417 if (gasok[14]) Init(nE, nB, nA, m_excLevels.size(), m_excRates, 0.);
418 if (gasok[15]) Init(nE, nB, nA, m_ionLevels.size(), m_ionRates, 0.);
419
420 // Force re-initialisation of collision rates etc.
421 m_isChanged = true;
422
423 if (m_debug) {
424 const std::string fmt = m_tab2d ? "3D" : "1D";
425 std::cout << m_className << "::LoadGasFile: Reading " << fmt << " table.\n";
426 }
427
428 // Drift velocity along E, Bt and ExB
429 double ve = 0., vb = 0., vx = 0.;
430 // Lorentz angle
431 double lor = 0.;
432 // Longitudinal and transverse diffusion coefficients
433 double dl = 0., dt = 0.;
434 // Townsend and attachment coefficients
435 double alpha = 0., alpha0 = 0., eta = 0.;
436 // Ion mobility and dissociation coefficient
437 double mu = 0., dis = 0.;
438 // Diffusion tensor.
439 std::array<double, 6> diff;
440 // Excitation and ionization rates.
441 const unsigned int nexc = m_excLevels.size();
442 std::vector<double> rexc(nexc, 0.);
443 const unsigned int nion = m_ionLevels.size();
444 std::vector<double> rion(nion, 0.);
445 for (int i = 0; i < nE; i++) {
446 for (int j = 0; j < nA; j++) {
447 for (int k = 0; k < nB; k++) {
448 if (m_tab2d) {
449 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
450 lor, dis, diff, rexc, rion);
451 } else {
452 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
453 lor, dis, diff, rexc, rion);
454 }
455 if (!m_eVelE.empty()) m_eVelE[j][k][i] = ve;
456 if (!m_eVelB.empty()) m_eVelB[j][k][i] = vb;
457 if (!m_eVelX.empty()) m_eVelX[j][k][i] = vx;
458 if (!m_eDifL.empty()) m_eDifL[j][k][i] = dl;
459 if (!m_eDifT.empty()) m_eDifT[j][k][i] = dt;
460 if (!m_eAlp.empty()) {
461 m_eAlp[j][k][i] = alpha;
462 m_eAlp0[j][k][i] = alpha0;
463 }
464 if (!m_eAtt.empty()) m_eAtt[j][k][i] = eta;
465 if (!m_iMob.empty()) m_iMob[j][k][i] = mu;
466 if (!m_eLor.empty()) m_eLor[j][k][i] = lor;
467 if (!m_iDis.empty()) m_iDis[j][k][i] = dis;
468 if (!m_eDifM.empty()) {
469 for (int l = 0; l < 6; l++) {
470 m_eDifM[l][j][k][i] = diff[l];
471 }
472 }
473 if (!m_excRates.empty()) {
474 for (unsigned int l = 0; l < nexc; ++l) {
475 m_excRates[l][j][k][i] = rexc[l];
476 }
477 }
478 if (!m_ionRates.empty()) {
479 for (unsigned int l = 0; l < nion; ++l) {
480 m_ionRates[l][j][k][i] = rion[l];
481 }
482 }
483 }
484 }
485 }
486
487 // Extrapolation methods
488 std::array<unsigned int, 13> extrapH = {{0}};
489 std::array<unsigned int, 13> extrapL = {{1}};
490 // Interpolation methods
491 std::array<unsigned int, 13> interp = {{2}};
492 // Ion diffusion coefficients.
493 double ionDiffL = 0.;
494 double ionDiffT = 0.;
495 // Gas pressure [Torr] and temperature [K].
496 double pgas = 0.;
497 double tgas = 0.;
498 // Moving on to the file footer
499 gasfile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
500 if (m_debug) std::cout << m_className << "::LoadGasFile: Reading footer.\n";
501 ReadFooter(gasfile, extrapH, extrapL, interp,
502 m_eThrAlp, m_eThrAtt, m_iThrDis, ionDiffL, ionDiffT, pgas, tgas);
503 gasfile.close();
504
505 // Decrement the threshold indices (compatibility with Fortran).
506 if (m_eThrAlp > 0) --m_eThrAlp;
507 if (m_eThrAtt > 0) --m_eThrAtt;
508 if (m_iThrDis > 0) --m_iThrDis;
509
510 // Set the reference pressure and temperature.
511 if (pgas > 0.) m_pressure = m_pressureTable = pgas;
512 if (tgas > 0.) m_temperature = m_temperatureTable = tgas;
513
514 // Multiply the E/p values by the pressure.
515 for (auto& field : m_eFields) field *= m_pressureTable;
516
517 // Scale the parameters.
518 const double sqrp = sqrt(m_pressureTable);
519 const double logp = log(m_pressureTable);
520 for (int i = nE; i--;) {
521 for (int j = nA; j--;) {
522 for (int k = nB; k--;) {
523 if (!m_eDifL.empty()) m_eDifL[j][k][i] /= sqrp;
524 if (!m_eDifT.empty()) m_eDifT[j][k][i] /= sqrp;
525 if (!m_eDifM.empty()) {
526 for (int l = 6; l--;) m_eDifM[l][j][k][i] /= m_pressureTable;
527 }
528 if (!m_eAlp.empty()) {
529 m_eAlp[j][k][i] += logp;
530 m_eAlp0[j][k][i] += logp;
531 }
532 if (!m_eAtt.empty()) m_eAtt[j][k][i] += logp;
533 if (!m_iDis.empty()) m_iDis[j][k][i] += logp;
534 /*
535 for (auto& exc : m_excRates) {
536 exc[j][k][i] /= m_pressureTable;
537 }
538 for (auto& ion : m_ionRates) {
539 ion[j][k][i] /= m_pressureTable;
540 }
541 */
542 }
543 }
544 }
545
546 // Decode the extrapolation and interpolation tables.
547 m_extrVel = {extrapL[0], extrapH[0]};
548 // Indices 1 and 2 correspond to velocities along Bt and ExB.
549 m_extrDif = {extrapL[3], extrapH[3]};
550 m_extrAlp = {extrapL[4], extrapH[4]};
551 m_extrAtt = {extrapL[5], extrapH[5]};
552 m_extrMob = {extrapL[6], extrapH[6]};
553 m_extrLor = {extrapL[7], extrapH[7]};
554 // Index 8: transverse diffusion.
555 m_extrDis = {extrapL[9], extrapH[9]};
556 // Index 10: diff. tensor
557 m_extrExc = {extrapL[11], extrapH[11]};
558 m_extrIon = {extrapL[12], extrapH[12]};
559 m_intpVel = interp[0];
560 m_intpDif = interp[3];
561 m_intpAlp = interp[4];
562 m_intpAtt = interp[5];
563 m_intpMob = interp[6];
564 m_intpLor = interp[7];
565 m_intpDis = interp[9];
566 m_intpExc = interp[11];
567 m_intpIon = interp[12];
568
569 // Ion diffusion
570 if (ionDiffL > 0.) Init(nE, nB, nA, m_iDifL, ionDiffL);
571 if (ionDiffT > 0.) Init(nE, nB, nA, m_iDifT, ionDiffT);
572
573 if (m_debug) std::cout << m_className << "::LoadGasFile: Done.\n";
574
575 return true;
576}
void ReadRecord3D(std::ifstream &gasfile, double &ve, double &vb, double &vx, double &dl, double &dt, double &alpha, double &alpha0, double &eta, double &mu, double &lor, double &dis, std::array< double, 6 > &dif, std::vector< double > &rexc, std::vector< double > &rion)
Definition: MediumGas.cc:755
std::pair< unsigned int, unsigned int > m_extrIon
Definition: MediumGas.hh:176
unsigned int m_intpIon
Definition: MediumGas.hh:178
void ResetTables() override
Reset all tables of transport parameters.
Definition: MediumGas.cc:2311
void ReadFooter(std::ifstream &gasfile, std::array< unsigned int, 13 > &extrapH, std::array< unsigned int, 13 > &extrapL, std::array< unsigned int, 13 > &interp, unsigned int &thrAlp, unsigned int &thrAtt, unsigned int &thrDis, double &ionDiffL, double &ionDiffT, double &pgas, double &tgas)
Definition: MediumGas.cc:813
void ReadRecord1D(std::ifstream &gasfile, double &ve, double &vb, double &vx, double &dl, double &dt, double &alpha, double &alpha0, double &eta, double &mu, double &lor, double &dis, std::array< double, 6 > &dif, std::vector< double > &rexc, std::vector< double > &rion)
Definition: MediumGas.cc:789
bool GetMixture(const std::vector< double > &mixture, const int version, std::vector< std::string > &gasnames, std::vector< double > &percentages) const
Definition: MediumGas.cc:907
std::pair< unsigned int, unsigned int > m_extrExc
Definition: MediumGas.hh:175
bool ReadHeader(std::ifstream &gasfile, int &version, std::bitset< 20 > &gasok, bool &is3d, std::vector< double > &mixture, std::vector< double > &efields, std::vector< double > &bfields, std::vector< double > &angles, std::vector< ExcLevel > &excLevels, std::vector< IonLevel > &ionLevels)
Definition: MediumGas.cc:578
unsigned int m_intpExc
Definition: MediumGas.hh:177
unsigned int m_intpMob
Definition: Medium.hh:603
unsigned int m_intpDis
Definition: Medium.hh:604
unsigned int m_intpDif
Definition: Medium.hh:599
std::pair< unsigned int, unsigned int > m_extrAtt
Definition: Medium.hh:592
std::pair< unsigned int, unsigned int > m_extrVel
Definition: Medium.hh:589
void Init(const size_t nE, const size_t nB, const size_t nA, std::vector< std::vector< std::vector< double > > > &tab, const double val)
Definition: Medium.cc:1304
unsigned int m_intpVel
Definition: Medium.hh:598
unsigned int m_intpAtt
Definition: Medium.hh:601
std::pair< unsigned int, unsigned int > m_extrDis
Definition: Medium.hh:595
std::pair< unsigned int, unsigned int > m_extrAlp
Definition: Medium.hh:591
unsigned int m_eThrAtt
Definition: Medium.hh:583
std::pair< unsigned int, unsigned int > m_extrLor
Definition: Medium.hh:593
unsigned int m_intpLor
Definition: Medium.hh:602
std::pair< unsigned int, unsigned int > m_extrDif
Definition: Medium.hh:590
unsigned int m_iThrDis
Definition: Medium.hh:586
std::pair< unsigned int, unsigned int > m_extrMob
Definition: Medium.hh:594
unsigned int m_eThrAlp
Definition: Medium.hh:582
unsigned int m_intpAlp
Definition: Medium.hh:600
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314

Referenced by GarfieldPhysics::InitializePhysics().

◆ LoadIonMobility()

bool Garfield::MediumGas::LoadIonMobility ( const std::string &  filename)

Read a table of ion mobilities as function of electric field from file.

Definition at line 2210 of file MediumGas.cc.

2210 {
2211 // Open the file.
2212 std::ifstream infile;
2213 infile.open(filename.c_str(), std::ios::in);
2214 // Make sure the file could actually be opened.
2215 if (!infile) {
2216 std::cerr << m_className << "::LoadIonMobility:\n"
2217 << " Error opening file " << filename << ".\n";
2218 ;
2219 return false;
2220 }
2221
2222 double field = -1., mu = -1.;
2223 double lastField = field;
2224 std::vector<double> efields;
2225 std::vector<double> mobilities;
2226
2227 // Read the file line by line.
2228 int i = 0;
2229 while (!infile.eof()) {
2230 ++i;
2231 // Read the next line.
2232 char line[100];
2233 infile.getline(line, 100);
2234 char* token = strtok(line, " ,\t");
2235 if (!token) {
2236 break;
2237 } else if (strcmp(token, "#") == 0 || strcmp(token, "*") == 0 ||
2238 strcmp(token, "//") == 0) {
2239 continue;
2240 } else {
2241 field = atof(token);
2242 token = strtok(NULL, " ,\t");
2243 if (!token) {
2244 std::cerr << m_className << "::LoadIonMobility:\n"
2245 << " Found E/N but no mobility before the end-of-line.\n"
2246 << " Skipping line " << i << ".\n";
2247 continue;
2248 }
2249 mu = atof(token);
2250 }
2251 token = strtok(NULL, " ,\t");
2252 if (token && strcmp(token, "//") != 0) {
2253 std::cerr << m_className << "::LoadIonMobility:\n"
2254 << " Unexpected non-comment characters after the mobility.\n"
2255 << " Skipping line " << i << ".\n";
2256 continue;
2257 }
2258 if (m_debug) {
2259 std::cout << " E/N = " << field << " Td: mu = " << mu << " cm2/(Vs)\n";
2260 }
2261 // Check if the data has been read correctly.
2262 if (infile.fail() && !infile.eof()) {
2263 std::cerr << m_className << "::LoadIonMobility:\n";
2264 std::cerr << " Error reading file\n";
2265 std::cerr << " " << filename << " (line " << i << ").\n";
2266 return false;
2267 }
2268 // Make sure the values make sense.
2269 // Negative field values are not allowed.
2270 if (field < 0.) {
2271 std::cerr << m_className << "::LoadIonMobility:\n";
2272 std::cerr << " Negative electric field (line " << i << ").\n";
2273 return false;
2274 }
2275 // The table has to be in ascending order.
2276 if (field <= lastField) {
2277 std::cerr << m_className << "::LoadIonMobility:\n";
2278 std::cerr << " Table is not in ascending order (line " << i << ").\n";
2279 return false;
2280 }
2281 // Add the values to the list.
2282 efields.push_back(field);
2283 mobilities.push_back(mu);
2284 lastField = field;
2285 }
2286
2287 const int ne = efields.size();
2288 if (ne <= 0) {
2289 std::cerr << m_className << "::LoadIonMobilities:\n";
2290 std::cerr << " No valid data found.\n";
2291 return false;
2292 }
2293
2294 // The E/N values in the file are supposed to be in Td (10^-17 V cm2).
2295 const double scaleField = 1.e-17 * GetNumberDensity();
2296 // The reduced mobilities in the file are supposed to be in cm2/(V s).
2297 const double scaleMobility = 1.e-9 * (AtmosphericPressure / m_pressure) *
2298 (m_temperature / ZeroCelsius);
2299 for (int j = ne; j--;) {
2300 // Scale the fields and mobilities.
2301 efields[j] *= scaleField;
2302 mobilities[j] *= scaleMobility;
2303 }
2304
2305 std::cout << m_className << "::LoadIonMobility:\n";
2306 std::cout << " Read " << ne << " values from file " << filename << "\n";
2307
2308 return SetIonMobility(efields, mobilities);
2309}
bool SetIonMobility(const std::vector< double > &fields, const std::vector< double > &mobilities)
Definition: Medium.cc:1044

◆ MergeGasFile()

bool Garfield::MediumGas::MergeGasFile ( const std::string &  filename,
const bool  replaceOld 
)

Read table of gas properties from and merge with the existing dataset.

Definition at line 944 of file MediumGas.cc.

945 {
946
947 // -----------------------------------------------------------------------
948 // GASMRG - Merges gas data from a file with existing gas tables.
949 // (Last changed on 16/ 2/11.)
950 // -----------------------------------------------------------------------
951
952 constexpr double eps = 1.e-3;
953
954 std::ifstream gasfile;
955 // Open the file.
956 gasfile.open(filename.c_str());
957 // Make sure the file could be opened.
958 if (!gasfile.is_open()) {
959 std::cerr << m_className << "::MergeGasFile:\n"
960 << " Cannot open file " << filename << ".\n";
961 return false;
962 }
963
964 int version = 12;
965 std::bitset<20> gasok;
966 bool is3d = false;
967 constexpr int nMagboltzGases = 60;
968 std::vector<double> mixture(nMagboltzGases, 0.);
969 std::vector<double> efields;
970 std::vector<double> bfields;
971 std::vector<double> angles;
972 std::vector<ExcLevel> excLevels;
973 std::vector<IonLevel> ionLevels;
974 if (!ReadHeader(gasfile, version, gasok, is3d, mixture, efields, bfields,
975 angles, excLevels, ionLevels)) {
976 std::cerr << m_className << "::MergeGasFile: Error reading header.\n",
977 gasfile.close();
978 return false;
979 }
980 // Check the version.
981 if (version != 12) {
982 std::cout << m_className << "::MergeGasFile:\n "
983 << "This dataset cannot be read because of a change in format.\n";
984 gasfile.close();
985 return false;
986 }
987
988 // Check the gas composition.
989 std::vector<std::string> gasnames;
990 std::vector<double> percentages;
991 if (!GetMixture(mixture, version, gasnames, percentages)) {
992 std::cerr << m_className << "::MergeGasFile:\n "
993 << "Cannot determine the gas composition.\n";
994 gasfile.close();
995 return false;
996 }
997 if (m_nComponents != gasnames.size()) {
998 std::cerr << m_className << "::MergeGasFile:\n "
999 << "Composition of the dataset differs from the present one.\n";
1000 gasfile.close();
1001 return false;
1002 }
1003
1004 for (unsigned int i = 0; i < m_nComponents; ++i) {
1005 const auto it = std::find(gasnames.begin(), gasnames.end(), m_gas[i]);
1006 if (it == gasnames.end()) {
1007 std::cerr << m_className << "::MergeGasFile:\n "
1008 << "Composition of the dataset differs from the present one.\n";
1009 gasfile.close();
1010 return false;
1011 }
1012 const double f2 = m_fraction[i];
1013 const double f1 = 0.01 * percentages[it - gasnames.begin()];
1014 if (fabs(f1 - f2) > 1.e-6 * (1. + fabs(f1) + fabs(f2))) {
1015 std::cerr << m_className << "::MergeGasFile:\n "
1016 << "Percentages of " << m_gas[i] << " differ.\n";
1017 gasfile.close();
1018 return false;
1019 }
1020 }
1021
1022 // Check that the excitations and ionisations match.
1023 const unsigned int nexc = excLevels.size();
1024 const unsigned int nion = ionLevels.size();
1025 bool excMatch = (m_excLevels.size() == nexc);
1026 if (excMatch) {
1027 for (unsigned int i = 0; i < nexc; ++i) {
1028 if (m_excLevels[i].label == excLevels[i].label) continue;
1029 excMatch = false;
1030 break;
1031 }
1032 }
1033 bool ionMatch = (m_ionLevels.size() == nion);
1034 if (ionMatch) {
1035 for (unsigned int i = 0; i < nion; ++i) {
1036 if (m_ionLevels[i].label == ionLevels[i].label) continue;
1037 ionMatch = false;
1038 break;
1039 }
1040 }
1041
1042 // Drift velocity along E, Bt and ExB
1043 double ve = 0., vb = 0., vx = 0.;
1044 // Lorentz angle
1045 double lor = 0.;
1046 // Longitudinal and transverse diffusion coefficients
1047 double dl = 0., dt = 0.;
1048 // Townsend and attachment coefficients
1049 double alpha = 0., alpha0 = 0., eta = 0.;
1050 // Ion mobility and dissociation coefficient
1051 double mu = 0., dis = 0.;
1052 // Diffusion tensor.
1053 std::array<double, 6> diff;
1054 // Excitation and ionization rates.
1055 std::vector<double> rexc(nexc, 0.);
1056 std::vector<double> rion(nion, 0.);
1057 // Loop through the gas tables to fast-forward to the footer.
1058 const unsigned int nNewE = efields.size();
1059 const unsigned int nNewB = bfields.size();
1060 const unsigned int nNewA = angles.size();
1061 for (unsigned int i = 0; i < nNewE; i++) {
1062 for (unsigned int j = 0; j < nNewA; j++) {
1063 for (unsigned int k = 0; k < nNewB; k++) {
1064 if (m_tab2d) {
1065 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1066 lor, dis, diff, rexc, rion);
1067 } else {
1068 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1069 lor, dis, diff, rexc, rion);
1070 }
1071 }
1072 }
1073 }
1074
1075 // Extrapolation methods
1076 std::array<unsigned int, 13> extrapH = {{0}};
1077 std::array<unsigned int, 13> extrapL = {{1}};
1078 // Interpolation methods
1079 std::array<unsigned int, 13> interp = {{2}};
1080 // Thresholds.
1081 unsigned int thrAlp = 0, thrAtt = 0, thrDis = 0;
1082 // Ion diffusion coefficients.
1083 double ionDiffL = 0., ionDiffT = 0.;
1084 // Gas pressure [Torr] and temperature [K].
1085 double pgas = 0., tgas = 0.;
1086 // Read the footer.
1087 gasfile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
1088 ReadFooter(gasfile, extrapH, extrapL, interp, thrAlp, thrAtt, thrDis,
1089 ionDiffL, ionDiffT, pgas, tgas);
1090
1091 // Check the pressure and temperature.
1092 if (!Similar(pgas, m_pressureTable, eps)) {
1093 std::cerr << m_className << "::MergeGasFile:\n "
1094 << "The gas pressure of the dataset to be read differs\n "
1095 << "from the current reference pressure; stop.\n";
1096 gasfile.close();
1097 return false;
1098 }
1099 if (!Similar(tgas, m_temperatureTable, eps)) {
1100 std::cerr << m_className << "::MergeGasFile:\n "
1101 << "The gas temperature of the dataset to be read differs\n "
1102 << "from the current reference temperature; stop.\n";
1103 gasfile.close();
1104 return false;
1105 }
1106
1107 // Go back to the start and re-read the header to get to the gas tables.
1108 gasfile.clear();
1109 gasfile.seekg(0);
1110 if (!ReadHeader(gasfile, version, gasok, is3d, mixture, efields, bfields,
1111 angles, excLevels, ionLevels)) {
1112 std::cerr << m_className << "::MergeGasFile: Error re-reading header.\n",
1113 gasfile.close();
1114 return false;
1115 }
1116
1117 // Multiply the E/p values by the pressure.
1118 for (auto& field : efields) field *= pgas;
1119
1120 if (m_debug) {
1121 std::cout << m_className << "::MergeGasFile:\n "
1122 << "Dataset to be merged has the following dimensions:\n "
1123 << "3D = " << is3d << " nE = " << nNewE << ", nB = " << nNewB
1124 << ", nA = " << nNewA << ", nExc = "
1125 << excLevels.size() << ", nIon = " << ionLevels.size() << "\n";
1126 }
1127
1128 unsigned int nE = m_eFields.size();
1129 unsigned int nB = m_bFields.size();
1130 unsigned int nA = m_bAngles.size();
1131 // Determine which mode we have to use for the E field.
1132 const int iemode = Equal(efields, m_eFields, eps);
1133 // Determine which mode we have to use for the angles.
1134 const int iamode = Equal(angles, m_bAngles, eps);
1135 // Determine which mode we have to use for the B field.
1136 const int ibmode = Equal(bfields, m_bFields, eps);
1137 if (m_debug) {
1138 std::cout << m_className << "::MergeGasFile:\n";
1139 if (iemode == 0) std::cout << " The E vectors differ.\n";
1140 else std::cout << " The E vectors are identical.\n";
1141 if (iamode == 0) std::cout << " The angle vectors differ.\n";
1142 else std::cout << " The angle vectors are identical.\n";
1143 if (ibmode == 0) std::cout << " The B vectors differ.\n";
1144 else std::cout << " The B vectors are identical.\n";
1145 }
1146 // Ensure there is a common mode.
1147 if (iemode + iamode + ibmode < 2) {
1148 std::cerr << m_className << "::MergeGasFile:\n Existing data and data "
1149 << "in the file don't have two common axes; not merged.\n";
1150 gasfile.close();
1151 return false;
1152 }
1153 // Decide whether we have to produce a 3D table or a 1D table.
1154 if ((is3d || ibmode * iamode == 0) && !m_tab2d) {
1155 if (m_debug) std::cout << " Expanding existing table to 3D mode.\n";
1156 m_tab2d = true;
1157 }
1158
1159 // Determine which data are currently present.
1160 std::bitset<20> existing;
1161 GetGasBits(existing);
1162 // If the grids don't match, warn for data being lost in the merge.
1163 if (iemode * ibmode * iamode == 0) {
1164 // Check for data currently present which are absent in the new data.
1165 if (existing[0] && !gasok[0]) {
1166 existing.reset(0);
1167 m_eVelE.clear();
1168 PrintAbsentInNew("drift velocity");
1169 }
1170 if (existing[1] && !gasok[1]) {
1171 existing.reset(1);
1172 m_iMob.clear();
1173 PrintAbsentInNew("ion mobility");
1174 }
1175 if (existing[2] && !gasok[2]) {
1176 existing.reset(2);
1177 m_eDifL.clear();
1178 PrintAbsentInNew("longitudinal diffusion");
1179 }
1180 if (existing[3] && !gasok[3]) {
1181 existing.reset(3);
1182 m_eAlp.clear();
1183 PrintAbsentInNew("Townsend coefficient");
1184 }
1185 if (existing[5] && !gasok[5]) {
1186 existing.reset(5);
1187 m_eAtt.clear();
1188 PrintAbsentInNew("attachment coefficient");
1189 }
1190 if (existing[6] && !gasok[6]) {
1191 existing.reset(6);
1192 m_eLor.clear();
1193 PrintAbsentInNew("Lorentz angle");
1194 }
1195 if (existing[7] && !gasok[7]) {
1196 existing.reset(7);
1197 m_eDifT.clear();
1198 PrintAbsentInNew("transverse diffusion");
1199 }
1200 if (existing[8] && !gasok[8]) {
1201 existing.reset(8);
1202 m_eVelB.clear();
1203 PrintAbsentInNew("velocity along Bt");
1204 }
1205 if (existing[9] && !gasok[9]) {
1206 existing.reset(9);
1207 m_eVelX.clear();
1208 PrintAbsentInNew("velocity along ExB");
1209 }
1210 if (existing[10] && !gasok[10]) {
1211 existing.reset(10);
1212 m_eDifM.clear();
1213 PrintAbsentInNew("diffusion tensor");
1214 }
1215 if (existing[11] && !gasok[11]) {
1216 existing.reset(11);
1217 m_iDis.clear();
1218 PrintAbsentInNew("ion dissociation data");
1219 }
1220 if (existing[14] && !gasok[14]) {
1221 existing.reset(14);
1222 m_excLevels.clear();
1223 m_excRates.clear();
1224 PrintAbsentInNew("excitation data");
1225 }
1226 if (existing[15] && !gasok[15]) {
1227 existing.reset(15);
1228 m_ionLevels.clear();
1229 m_ionRates.clear();
1230 PrintAbsentInNew("ionisation data");
1231 }
1232 // And for data present in the file but not currently present.
1233 if (!existing[0] && gasok[0]) {
1234 gasok.reset(0);
1235 PrintAbsentInExisting("drift velocity");
1236 }
1237 if (!existing[1] && gasok[1]) {
1238 gasok.reset(1);
1239 PrintAbsentInExisting("ion mobility");
1240 }
1241 if (!existing[2] && gasok[2]) {
1242 gasok.reset(2);
1243 PrintAbsentInExisting("longitudinal diffusion");
1244 }
1245 if (!existing[3] && gasok[3]) {
1246 gasok.reset(3);
1247 PrintAbsentInExisting("Townsend coefficient");
1248 }
1249 if (!existing[5] && gasok[5]) {
1250 gasok.reset(5);
1251 PrintAbsentInExisting("attachment coefficient");
1252 }
1253 if (!existing[6] && gasok[6]) {
1254 gasok.reset(6);
1255 PrintAbsentInExisting("Lorentz angle");
1256 }
1257 if (!existing[7] && gasok[7]) {
1258 gasok.reset(7);
1259 PrintAbsentInExisting("transverse diffusion");
1260 }
1261 if (!existing[8] && gasok[8]) {
1262 gasok.reset(8);
1263 PrintAbsentInExisting("velocity along Bt");
1264 }
1265 if (!existing[9] && gasok[9]) {
1266 gasok.reset(9);
1267 PrintAbsentInExisting("velocity along ExB");
1268 }
1269 if (!existing[10] && gasok[10]) {
1270 gasok.reset(10);
1271 PrintAbsentInExisting("diffusion tensor");
1272 }
1273 if (!existing[11] && gasok[11]) {
1274 gasok.reset(11);
1275 PrintAbsentInExisting("ion dissociation data");
1276 }
1277 if (!existing[14] && gasok[14]) {
1278 gasok.reset(14);
1279 PrintAbsentInExisting("excitation data");
1280 }
1281 if (!existing[15] && gasok[15]) {
1282 gasok.reset(15);
1283 PrintAbsentInExisting("ionisation data");
1284 }
1285 if (existing[14] && gasok[14] && !excMatch) {
1286 std::cerr << " Excitation levels of the two datasets don't match.\n"
1287 << " Deleting excitation data.\n";
1288 m_excLevels.clear();
1289 m_excRates.clear();
1290 existing.reset(14);
1291 gasok.reset(14);
1292 }
1293 if (existing[15] && gasok[15] && !ionMatch) {
1294 std::cerr << " Ionisation levels of the two datasets don't match.\n"
1295 << " Deleting ionisation data.\n";
1296 m_ionLevels.clear();
1297 m_ionRates.clear();
1298 existing.reset(15);
1299 gasok.reset(15);
1300 }
1301 // TODO: if the existing dataset is 1D (B = 0), then there's no need
1302 // to reset the Lorentz angle and the drift velocities || Bt and || ExB.
1303 } else {
1304 // If the grids are identical, initialise the tables that are only present
1305 // in the new dataset but not in existing one.
1306 if (gasok[0] && !existing[0]) Init(nE, nB, nA, m_eVelE, 0.);
1307 if (gasok[1] && !existing[1]) Init(nE, nB, nA, m_iMob, 0.);
1308 if (gasok[2] && !existing[2]) Init(nE, nB, nA, m_eDifL, 0.);
1309 if (gasok[3] && !existing[3]) {
1310 Init(nE, nB, nA, m_eAlp, -30.);
1311 Init(nE, nB, nA, m_eAlp0, -30.);
1312 }
1313 if (gasok[5] && !existing[5]) Init(nE, nB, nA, m_eAtt, -30.);
1314 if (gasok[6] && !existing[6]) Init(nE, nB, nA, m_eLor, -30.);
1315 if (gasok[7] && !existing[7]) Init(nE, nB, nA, m_eDifT, 0.);
1316 if (gasok[8] && !existing[8]) Init(nE, nB, nA, m_eVelB, 0.);
1317 if (gasok[9] && !existing[9]) Init(nE, nB, nA, m_eVelX, 0.);
1318 if (gasok[10] && !existing[10]) Init(nE, nB, nA, 6, m_eDifM, 0.);
1319 if (gasok[11] && !existing[11]) Init(nE, nB, nA, m_iDis, -30.);
1320 if (gasok[14] && (!existing[14] || replaceOld)) {
1321 Init(nE, nB, nA, nexc, m_excRates, 0.);
1322 }
1323 if (gasok[15] && (!existing[15] || replaceOld)) {
1324 Init(nE, nB, nA, nion, m_ionRates, 0.);
1325 }
1326 }
1327
1328 // Initialise the "new" flags.
1329 std::vector<bool> newE(nE, false);
1330 std::vector<bool> newA(nA, false);
1331 std::vector<bool> newB(nB, false);
1332 // Extend the existing tables.
1333 std::cout << m_className << "::MergeGasFile: Extending the tables.\n";
1334 // Insert room in the tables for new columns in E.
1335 if (iemode == 0) {
1336 // Loop over the new values.
1337 for (const auto efield : efields) {
1338 // Loop over the old values.
1339 bool found = false;
1340 for (unsigned int j = 0; j < nE; ++j) {
1341 // If it overlaps with existing E, either keep old or new data.
1342 if (Similar(efield, m_eFields[j], eps)) {
1343 if (replaceOld) {
1344 std::cout << " Replacing existing data for E = "
1345 << m_eFields[j] << " V/cm by data from file.\n";
1346 m_eFields[j] = efield;
1347 newE[j] = true;
1348 ZeroRowE(j, nB, nA);
1349 } else {
1350 std::cout << " Keeping existing data for E = " << m_eFields[j]
1351 << " V/cm, not using data from the file.\n";
1352 }
1353 found = true;
1354 break;
1355 } else if (efield < m_eFields[j]) {
1356 // Otherwise shift all data at higher E values.
1357 if (m_debug) {
1358 std::cout << " Inserting E = " << efield
1359 << " V/cm at slot " << j << ".\n";
1360 }
1361 InsertE(j, nE, nB, nA);
1362 m_eFields.insert(m_eFields.begin() + j, efield);
1363 newE.insert(newE.begin() + j, true);
1364 ZeroRowE(j, nB, nA);
1365 ++nE;
1366 found = true;
1367 break;
1368 }
1369 }
1370 if (found) continue;
1371 // If there is no higher E, then add the line at the end.
1372 if (m_debug) {
1373 std::cout << " Adding E = " << efield << " V/cm at the end.\n";
1374 }
1375 InsertE(nE, nE, nB, nA);
1376 m_eFields.push_back(efield);
1377 newE.push_back(true);
1378 ZeroRowE(nE, nB, nA);
1379 ++nE;
1380 }
1381 }
1382 // Insert room in the tables for new columns in B.
1383 if (ibmode == 0) {
1384 // Loop over the new values.
1385 for (const auto bfield : bfields) {
1386 // Loop over the old values.
1387 bool found = false;
1388 for (unsigned int j = 0; j < nB; ++j) {
1389 // If it overlaps with existing B, either keep old or new data.
1390 if (Similar(bfield, m_bFields[j], eps)) {
1391 if (replaceOld) {
1392 std::cout << " Replacing old data for B = " << m_bFields[j]
1393 << " T by data from file.\n";
1394 m_bFields[j] = bfield;
1395 newB[j] = true;
1396 ZeroRowB(j, nE, nA);
1397 } else {
1398 std::cout << " Keeping old data for B = " << m_bFields[j]
1399 << " T, not using data from file.\n";
1400 }
1401 found = true;
1402 break;
1403 } else if (bfield < m_bFields[j]) {
1404 // Otherwise shift all data at higher B values.
1405 if (m_debug) {
1406 std::cout << " Inserting B = " << bfield << " T at slot "
1407 << j << ".\n";
1408 }
1409 InsertB(j, nE, nB, nA);
1410 m_bFields.insert(m_bFields.begin() + j, bfield);
1411 newB.insert(newB.begin() + j, true);
1412 ZeroRowB(j, nE, nA);
1413 ++nB;
1414 found = true;
1415 break;
1416 }
1417 }
1418 if (found) continue;
1419 // If there is no higher B, then add the line at the end.
1420 if (m_debug) {
1421 std::cout << " Adding B = " << bfield << " T at the end.\n";
1422 }
1423 InsertB(nB, nE, nB, nA);
1424 m_bFields.push_back(bfield);
1425 newB.push_back(true);
1426 ZeroRowB(nB, nE, nA);
1427 ++nB;
1428 }
1429 }
1430 // Insert room in the tables for new columns in angle.
1431 if (iamode == 0) {
1432 // Loop over the new values.
1433 for (const auto angle : angles) {
1434 // Loop over the old values.
1435 bool found = false;
1436 for (unsigned int j = 0; j < nA; ++j) {
1437 // If it overlaps with an existing angle, either keep old or new data.
1438 if (Similar(angle, m_bAngles[j], eps)) {
1439 if (replaceOld) {
1440 std::cout << " Replacing old data for angle(E,B) = "
1441 << m_bAngles[j] * RadToDegree
1442 << " degrees by data from the file.\n";
1443 m_bAngles[j] = angle;
1444 newA[j] = true;
1445 ZeroRowA(j, nE, nB);
1446 } else {
1447 std::cout << " Keeping old data for angle(E,B) = "
1448 << m_bAngles[j] * RadToDegree
1449 << " degrees, not using data from file.\n";
1450 }
1451 found = true;
1452 break;
1453 } else if (angle < m_bAngles[j]) {
1454 // Otherwise shift all data at higher angles.
1455 if (m_debug) {
1456 std::cout << " Inserting angle = " << angle * RadToDegree
1457 << " degrees at slot " << j << ".\n";
1458 }
1459 InsertA(j, nE, nB, nA);
1460 m_bAngles.insert(m_bAngles.begin() + j, angle);
1461 newA.insert(newA.begin() + j, true);
1462 ZeroRowA(j, nE, nB);
1463 ++nA;
1464 found = true;
1465 break;
1466 }
1467 }
1468 if (found) continue;
1469 // If there is no higher angle, then add the line at the end.
1470 if (m_debug) {
1471 std::cout << " Adding angle = " << angle * RadToDegree
1472 << " degrees at the end.\n";
1473 }
1474 InsertA(nA, nE, nB, nA);
1475 m_bAngles.push_back(angle);
1476 newA.push_back(true);
1477 ZeroRowA(nA, nE, nB);
1478 ++nA;
1479 }
1480 }
1481
1482 const double sqrp = sqrt(pgas);
1483 const double logp = log(pgas);
1484
1485 // Read the gas table.
1486 for (const auto efield : efields) {
1487 // Locate the index at which these values are to be stored.
1488 const int inde = FindIndex(efield, m_eFields, eps);
1489 for (const auto angle : angles) {
1490 const int inda = FindIndex(angle, m_bAngles, eps);
1491 for (const auto bfield : bfields) {
1492 // Read the record.
1493 if (is3d) {
1494 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1495 lor, dis, diff, rexc, rion);
1496 } else {
1497 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1498 lor, dis, diff, rexc, rion);
1499 }
1500 const int indb = FindIndex(bfield, m_bFields, eps);
1501 if (inde < 0 || inda < 0 || indb < 0) {
1502 std::cerr << m_className << "::MergeGasFile:\n Unable to locate"
1503 << " the (E,angle,B) insertion point; no gas data read.\n";
1504 std::cout << "BFIELD = " << bfield << ", IB = " << indb << "\n";
1505 ResetTables();
1506 gasfile.close();
1507 return false;
1508 }
1509 const bool update = newE[inde] || newA[inda] || newB[indb] || replaceOld;
1510 // Store the data.
1511 if (gasok[0] && (update || !existing[0])) {
1512 m_eVelE[inda][indb][inde] = ve;
1513 }
1514 if (gasok[1] && (update || !existing[1])) {
1515 m_iMob[inda][indb][inde] = mu;
1516 }
1517 if (gasok[2] && (update || !existing[2])) {
1518 m_eDifL[inda][indb][inde] = dl / sqrp;
1519 }
1520 if (gasok[3] && (update || !existing[3])) {
1521 m_eAlp[inda][indb][inde] = alpha + logp;
1522 m_eAlp0[inda][indb][inde] = alpha0 + logp;
1523 }
1524 if (gasok[5] && (update || !existing[5])) {
1525 m_eAtt[inda][indb][inde] = eta + logp;
1526 }
1527 if (gasok[6] && (update || !existing[6])) {
1528 m_eLor[inda][indb][inde] = lor;
1529 }
1530 if (gasok[7] && (update || !existing[7])) {
1531 m_eDifT[inda][indb][inde] = dt / sqrp;
1532 }
1533 if (gasok[8] && (update || !existing[8])) {
1534 m_eVelB[inda][indb][inde] = vb;
1535 }
1536 if (gasok[9] && (update || !existing[9])) {
1537 m_eVelX[inda][indb][inde] = vx;
1538 }
1539 if (gasok[10] && (update || !existing[10])) {
1540 for (unsigned int l = 0; l < 6; ++l) {
1541 m_eDifM[l][inda][indb][inde] = diff[l] / pgas;
1542 }
1543 }
1544 if (gasok[11] && (update || !existing[11])) {
1545 m_iDis[inda][indb][inde] = dis + logp;
1546 }
1547 if (gasok[14] && (update || !existing[14])) {
1548 for (unsigned int l = 0; l < nexc; ++l) {
1549 m_excRates[l][inda][indb][inde] = rexc[l];
1550 }
1551 }
1552 if (gasok[15] && (update || !existing[15])) {
1553 for (unsigned int l = 0; l < nion; ++l) {
1554 m_ionRates[l][inda][indb][inde] = rion[l];
1555 }
1556 }
1557 }
1558 }
1559 }
1560 // if (iemode + iamode + ibmode == 3) { ... }
1561 if (replaceOld) {
1562 if (m_debug) {
1563 std::cout << m_className << "::MergeGasFile: "
1564 << "Replacing extrapolation and interpolation data.\n";
1565 }
1566 if (gasok[0]) m_extrVel = {extrapL[0], extrapH[0]};
1567 if (gasok[1]) m_extrMob = {extrapL[6], extrapH[6]};
1568 if (gasok[2]) m_extrDif = {extrapL[3], extrapH[3]};
1569 if (gasok[3]) m_extrAlp = {extrapL[4], extrapH[4]};
1570 if (gasok[5]) m_extrAtt = {extrapL[5], extrapH[5]};
1571 if (gasok[6]) m_extrLor = {extrapL[7], extrapH[7]};
1572 if (gasok[11]) m_extrDis = {extrapL[9], extrapH[9]};
1573 if (gasok[14]) m_extrExc = {extrapL[11], extrapH[11]};
1574 if (gasok[15]) m_extrIon = {extrapL[12], extrapH[12]};
1575
1576 if (gasok[0]) m_intpVel = interp[0];
1577 if (gasok[1]) m_intpMob = interp[6];
1578 if (gasok[2]) m_intpDif = interp[3];
1579 if (gasok[3]) m_intpAlp = interp[4];
1580 if (gasok[5]) m_intpAtt = interp[5];
1581 if (gasok[6]) m_intpLor = interp[7];
1582 if (gasok[11]) m_intpDis = interp[9];
1583 if (gasok[14]) m_intpExc = interp[11];
1584 if (gasok[15]) m_intpIon = interp[12];
1585
1586 // Ion diffusion.
1587 if (m_debug && (ionDiffL > 0. || ionDiffT > 0.)) {
1588 std::cout << m_className << "::MergeGasFile: Replacing ion diffusion.\n";
1589 }
1590 if (ionDiffL > 0.) Init(nE, nB, nA, m_iDifL, ionDiffL);
1591 if (ionDiffT > 0.) Init(nE, nB, nA, m_iDifT, ionDiffT);
1592 }
1593 // Update the Townsend and attachment threshold indices.
1596 return true;
1597}
void InsertB(const int ib, const int ne, const int nb, const int na)
Definition: MediumGas.cc:1641
void GetGasBits(std::bitset< 20 > &gasok) const
Definition: MediumGas.cc:2047
void ZeroRowA(const int ia, const int ne, const int nb)
Definition: MediumGas.cc:1747
void ZeroRowB(const int ib, const int ne, const int na)
Definition: MediumGas.cc:1739
void ZeroRowE(const int ie, const int nb, const int na)
Definition: MediumGas.cc:1731
void InsertA(const int ia, const int ne, const int nb, const int na)
Definition: MediumGas.cc:1689
void InsertE(const int ie, const int ne, const int nb, const int na)
Definition: MediumGas.cc:1599
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:615

◆ PrintGas()

void Garfield::MediumGas::PrintGas ( )
virtual

Print information about the present gas mixture and available data.

Reimplemented in Garfield::MediumMagboltz.

Definition at line 2067 of file MediumGas.cc.

2067 {
2068 // Print a summary.
2069 std::cout << m_className << "::PrintGas:\n"
2070 << " Gas composition: " << m_name;
2071 if (m_nComponents > 1) {
2072 std::cout << " (" << m_fraction[0] * 100;
2073 for (unsigned int i = 1; i < m_nComponents; ++i) {
2074 std::cout << "/" << m_fraction[i] * 100;
2075 }
2076 std::cout << ")";
2077 }
2078 std::cout << "\n";
2079 std::cout << " Pressure: " << m_pressure << " Torr\n"
2080 << " Temperature: " << m_temperature << " K\n"
2081 << " Gas file:\n"
2082 << " Pressure: " << m_pressureTable << " Torr\n"
2083 << " Temperature: " << m_temperatureTable << " K\n";
2084 if (m_eFields.size() > 1) {
2085 std::cout << " Electric field range: " << m_eFields[0] << " - "
2086 << m_eFields.back() << " V/cm in " << m_eFields.size() - 1
2087 << " steps.\n";
2088 } else if (m_eFields.size() == 1) {
2089 std::cout << " Electric field: " << m_eFields[0] << " V/cm\n";
2090 } else {
2091 std::cout << " Electric field range: not set\n";
2092 }
2093 if (m_bFields.size() > 1) {
2094 std::cout << " Magnetic field range: " << m_bFields[0] << " - "
2095 << m_bFields.back() << " T in " << m_bFields.size() - 1
2096 << " steps.\n";
2097 } else if (m_bFields.size() == 1) {
2098 std::cout << " Magnetic field: " << m_bFields[0] << " T\n";
2099 } else {
2100 std::cout << " Magnetic field range: not set\n";
2101 }
2102 if (m_bAngles.size() > 1) {
2103 std::cout << " Angular range: " << m_bAngles[0] << " - "
2104 << m_bAngles.back() << " rad in " << m_bAngles.size() - 1
2105 << " steps.\n";
2106 } else if (m_bAngles.size() == 1) {
2107 std::cout << " Angle between E and B: " << m_bAngles[0] << " rad\n";
2108 } else {
2109 std::cout << " Angular range: not set\n";
2110 }
2111
2112 std::cout << " Available electron transport data:\n";
2113 if (!m_eVelE.empty()) {
2114 std::cout << " Velocity along E\n";
2115 }
2116 if (!m_eVelB.empty()) {
2117 std::cout << " Velocity along Bt\n";
2118 }
2119 if (!m_eVelX.empty()) {
2120 std::cout << " Velocity along ExB\n";
2121 }
2122 if (!(m_eVelE.empty() && m_eVelB.empty() &&
2123 m_eVelX.empty())) {
2124 PrintExtrapolation(m_extrVel);
2125 std::cout << " Interpolation order: " << m_intpVel << "\n";
2126 }
2127 if (!m_eDifL.empty()) {
2128 std::cout << " Longitudinal diffusion coefficient\n";
2129 }
2130 if (!m_eDifT.empty()) {
2131 std::cout << " Transverse diffusion coefficient\n";
2132 }
2133 if (!m_eDifM.empty()) {
2134 std::cout << " Diffusion tensor\n";
2135 }
2136 if (!m_eDifL.empty() || !m_eDifT.empty() || !m_eDifM.empty()) {
2137 PrintExtrapolation(m_extrDif);
2138 std::cout << " Interpolation order: " << m_intpDif << "\n";
2139 }
2140 if (!m_eAlp.empty()) {
2141 std::cout << " Townsend coefficient\n";
2142 PrintExtrapolation(m_extrAlp);
2143 std::cout << " Interpolation order: " << m_intpAlp << "\n";
2144 }
2145 if (!m_eAtt.empty()) {
2146 std::cout << " Attachment coefficient\n";
2147 PrintExtrapolation(m_extrAtt);
2148 std::cout << " Interpolation order: " << m_intpAtt << "\n";
2149 }
2150 if (!m_eLor.empty()) {
2151 std::cout << " Lorentz Angle\n";
2152 PrintExtrapolation(m_extrLor);
2153 std::cout << " Interpolation order: " << m_intpLor << "\n";
2154 }
2155 if (!m_excRates.empty()) {
2156 std::cout << " Excitation rates\n";
2157 for (const auto& exc : m_excLevels) {
2158 std::cout << " " << exc.label << "\n";
2159 std::cout << " Energy = " << exc.energy << " eV";
2160 if (exc.prob > 0.) {
2161 std::cout << ", Penning transfer probability = " << exc.prob;
2162 }
2163 std::cout << "\n";
2164 }
2165 PrintExtrapolation(m_extrExc);
2166 std::cout << " Interpolation order: " << m_intpExc << "\n";
2167 }
2168 if (!m_ionRates.empty()) {
2169 std::cout << " Ionisation rates\n";
2170 for (const auto& ion : m_ionLevels) {
2171 std::cout << " " << ion.label << "\n";
2172 std::cout << " Threshold = " << ion.energy << " eV\n";
2173 }
2174 PrintExtrapolation(m_extrIon);
2175 std::cout << " Interpolation order: " << m_intpIon << "\n";
2176 }
2177 if (m_eVelE.empty() && m_eVelB.empty() && m_eVelX.empty() &&
2178 m_eDifL.empty() && m_eDifT.empty() && m_eDifM.empty() &&
2179 m_eAlp.empty() && m_eAtt.empty() && m_excRates.empty() &&
2180 m_ionRates.empty() && m_eLor.empty()) {
2181 std::cout << " none\n";
2182 }
2183
2184 std::cout << " Available ion transport data:\n";
2185 if (!m_iMob.empty()) {
2186 std::cout << " Mobility\n";
2187 PrintExtrapolation(m_extrMob);
2188 std::cout << " Interpolation order: " << m_intpMob << "\n";
2189 }
2190 if (!m_iDifL.empty()) {
2191 std::cout << " Longitudinal diffusion coefficient\n";
2192 }
2193 if (!m_iDifT.empty()) {
2194 std::cout << " Transverse diffusion coefficient\n";
2195 }
2196 if (!m_iDifL.empty() || !m_iDifT.empty()) {
2197 PrintExtrapolation(m_extrDif);
2198 std::cout << " Interpolation order: " << m_intpDif << "\n";
2199 }
2200 if (!m_iDis.empty()) {
2201 std::cout << " Dissociation coefficient\n";
2202 PrintExtrapolation(m_extrDis);
2203 std::cout << " Interpolation order: " << m_intpDis << "\n";
2204 }
2205 if (m_iMob.empty() && m_iDifL.empty() && m_iDifT.empty() && m_iDis.empty()) {
2206 std::cout << " none\n";
2207 }
2208}

Referenced by Garfield::MediumMagboltz::PrintGas().

◆ ReadFooter()

void Garfield::MediumGas::ReadFooter ( std::ifstream &  gasfile,
std::array< unsigned int, 13 > &  extrapH,
std::array< unsigned int, 13 > &  extrapL,
std::array< unsigned int, 13 > &  interp,
unsigned int &  thrAlp,
unsigned int &  thrAtt,
unsigned int &  thrDis,
double &  ionDiffL,
double &  ionDiffT,
double &  pgas,
double &  tgas 
)
protected

Definition at line 813 of file MediumGas.cc.

819 {
820
821 bool done = false;
822 while (!done) {
823 char line[256];
824 gasfile.getline(line, 256);
825 char* token = strtok(line, " :,%=\t");
826 while (token) {
827 if (strcmp(token, "H") == 0) {
828 token = strtok(NULL, " :,%=\t");
829 for (int i = 0; i < 13; i++) {
830 token = strtok(NULL, " :,%=\t");
831 if (token != NULL) extrapH[i] = atoi(token);
832 }
833 } else if (strcmp(token, "L") == 0) {
834 token = strtok(NULL, " :,%=\t");
835 for (int i = 0; i < 13; i++) {
836 token = strtok(NULL, " :,%=\t");
837 if (token != NULL) extrapL[i] = atoi(token);
838 }
839 } else if (strcmp(token, "Thresholds") == 0) {
840 token = strtok(NULL, " :,%=\t");
841 if (token != NULL) thrAlp = atoi(token);
842 token = strtok(NULL, " :,%=\t");
843 if (token != NULL) thrAtt = atoi(token);
844 token = strtok(NULL, " :,%=\t");
845 if (token != NULL) thrDis = atoi(token);
846 } else if (strcmp(token, "Interp") == 0) {
847 for (int i = 0; i < 13; i++) {
848 token = strtok(NULL, " :,%=\t");
849 if (token != NULL) interp[i] = atoi(token);
850 }
851 } else if (strcmp(token, "A") == 0) {
852 token = strtok(NULL, " :,%=\t");
853 // Parameter for energy loss distribution, currently not used
854 // double a;
855 // if (token != NULL) a = atof(token);
856 } else if (strcmp(token, "Z") == 0) {
857 // Parameter for energy loss distribution, currently not used
858 token = strtok(NULL, " :,%=\t");
859 // double z;
860 // if (token != NULL) z = atof(token);
861 } else if (strcmp(token, "EMPROB") == 0) {
862 // Parameter for energy loss distribution, currently not used
863 token = strtok(NULL, " :,%=\t");
864 // double emprob;
865 // if (token != NULL) emprob = atof(token);
866 } else if (strcmp(token, "EPAIR") == 0) {
867 // Parameter for energy loss distribution, currently not used
868 token = strtok(NULL, " :,%=\t");
869 // double epair;
870 // if (token != NULL) epair = atof(token);
871 } else if (strcmp(token, "Ion") == 0) {
872 // Ion diffusion coefficients
873 token = strtok(NULL, " :,%=\t");
874 token = strtok(NULL, " :,%=\t");
875 if (token != NULL) ionDiffL = atof(token);
876 token = strtok(NULL, " :,%=\t");
877 if (token != NULL) ionDiffT = atof(token);
878 } else if (strcmp(token, "CMEAN") == 0) {
879 // Cluster parameter, currently not used
880 token = strtok(NULL, " :,%=\t");
881 // double clsPerCm;
882 // if (token != NULL) clsPerCm = atof(token);
883 } else if (strcmp(token, "RHO") == 0) {
884 // Parameter for energy loss distribution, currently not used
885 token = strtok(NULL, " :,%=\t");
886 // double rho;
887 // if (token != NULL) rho = atof(token);
888 } else if (strcmp(token, "PGAS") == 0) {
889 // Pressure [Torr]
890 token = strtok(NULL, " :,%=\t");
891 if (token != NULL) pgas = atof(token);
892 } else if (strcmp(token, "TGAS") == 0) {
893 // Temperature [K]
894 token = strtok(NULL, " :,%=\t");
895 if (token != NULL) tgas = atof(token);
896 done = true;
897 break;
898 } else {
899 done = true;
900 break;
901 }
902 token = strtok(NULL, " :,%=\t");
903 }
904 }
905}

Referenced by LoadGasFile(), and MergeGasFile().

◆ ReadHeader()

bool Garfield::MediumGas::ReadHeader ( std::ifstream &  gasfile,
int &  version,
std::bitset< 20 > &  gasok,
bool &  is3d,
std::vector< double > &  mixture,
std::vector< double > &  efields,
std::vector< double > &  bfields,
std::vector< double > &  angles,
std::vector< ExcLevel > &  excLevels,
std::vector< IonLevel > &  ionLevels 
)
protected

Definition at line 578 of file MediumGas.cc.

582 {
583
584 gasok.reset();
585 bool done = false;
586 while (!done) {
587 char line[256];
588 gasfile.getline(line, 256);
589 const bool quotes = (strstr(line, "\"") != NULL);
590 if (strncmp(line, " The gas tables follow:", 8) == 0 ||
591 strncmp(line, "The gas tables follow:", 7) == 0) {
592 done = true;
593 break;
594 }
595 char* token = strtok(line, " :,%");
596 while (token) {
597 if (strcmp(token, "Version") == 0) {
598 token = strtok(NULL, " :,%");
599 version = atoi(token);
600 // Check the version number.
601 if (version != 10 && version != 11 && version != 12) {
602 std::cerr << m_className << "::ReadHeader:\n"
603 << " The file has version number " << version << ".\n"
604 << " Files written in this format cannot be read.\n";
605 return false;
606 }
607 } else if (strcmp(token, "GASOK") == 0) {
608 // Get the GASOK bits indicating if a parameter
609 // is present in the table (T) or not (F).
610 token = strtok(NULL, " :,%\t");
611 token = strtok(NULL, " :,%\t");
612 std::string okstr(token);
613 if (m_debug) std::cout << " GASOK bits: " << okstr << "\n";
614 if (okstr.size() < 20) {
615 std::cerr << m_className << "::ReadHeader:\n"
616 << " Unexpected size of GASOK string ("
617 << okstr.size() << ").\n";
618 return false;
619 }
620 for (unsigned int i = 0; i < 20; ++i) {
621 if (okstr[i] == 'T') gasok.set(i);
622 }
623 } else if (strcmp(token, "Identifier") == 0) {
624 // Get the identification string.
625 std::string identifier = "";
626 token = strtok(NULL, "\n");
627 if (token != NULL) identifier += token;
628 if (m_debug) std::cout << " Identifier: " << identifier << "\n";
629 } else if (strcmp(token, "Dimension") == 0) {
630 token = strtok(NULL, " :,%\t");
631 if (strcmp(token, "F") == 0) {
632 is3d = false;
633 } else {
634 is3d = true;
635 }
636 token = strtok(NULL, " :,%\t");
637 const int nE = atoi(token);
638 // Check the number of E points.
639 if (nE <= 0) {
640 std::cerr << m_className << "::ReadHeader:\n"
641 << " Number of E fields out of range.\n";
642 return false;
643 }
644 token = strtok(NULL, " :,%\t");
645 const int nA = atoi(token);
646 // Check the number of angles.
647 if (is3d && nA <= 0) {
648 std::cerr << m_className << "::ReadHeader:\n"
649 << " Number of E-B angles out of range.\n";
650 return false;
651 }
652 token = strtok(NULL, " :,%\t");
653 const int nB = atoi(token);
654 // Check the number of B points.
655 if (is3d && nB <= 0) {
656 std::cerr << m_className << "::ReadHeader:\n"
657 << " Number of B fields out of range.\n";
658 return false;
659 }
660 efields.resize(nE);
661 angles.resize(nA);
662 bfields.resize(nB);
663 // Fill in the excitation/ionisation structs
664 // Excitation
665 token = strtok(NULL, " :,%\t");
666 const int nexc = atoi(token);
667 // Ionization
668 token = strtok(NULL, " :,%\t");
669 const int nion = atoi(token);
670 if (m_debug) {
671 std::cout << " " << nexc << " excitations, " << nion
672 << " ionisations.\n";
673 }
674 } else if (strcmp(token, "E") == 0) {
675 token = strtok(NULL, " :,%");
676 if (strncmp(token, "fields", 6) == 0) {
677 const int nE = efields.size();
678 for (int i = 0; i < nE; ++i) gasfile >> efields[i];
679 }
680 } else if (strcmp(token, "E-B") == 0) {
681 token = strtok(NULL, " :,%");
682 if (strncmp(token, "angles", 6) == 0) {
683 const int nA = angles.size();
684 for (int i = 0; i < nA; ++i) gasfile >> angles[i];
685 }
686 } else if (strcmp(token, "B") == 0) {
687 token = strtok(NULL, " :,%");
688 if (strncmp(token, "fields", 6) == 0) {
689 double bstore = 0.;
690 const int nB = bfields.size();
691 for (int i = 0; i < nB; i++) {
692 gasfile >> bstore;
693 bfields[i] = bstore / 100.;
694 }
695 }
696 } else if (strcmp(token, "Mixture") == 0) {
697 const unsigned int nMagboltzGases = mixture.size();
698 for (unsigned int i = 0; i < nMagboltzGases; ++i) {
699 gasfile >> mixture[i];
700 }
701 } else if (strcmp(token, "Excitation") == 0) {
702 // Skip number.
703 token = strtok(NULL, " :,%");
704 ExcLevel exc;
705 // Get label.
706 if (quotes) {
707 token = strtok(NULL, "\"");
708 token = strtok(NULL, "\"");
709 } else {
710 token = strtok(NULL, " :,%");
711 }
712 exc.label = token;
713 // Get energy.
714 token = strtok(NULL, " :,%");
715 exc.energy = atof(token);
716 // Get Penning probability.
717 token = strtok(NULL, " :,%");
718 exc.prob = atof(token);
719 exc.rms = 0.;
720 exc.dt = 0.;
721 if (version >= 11) {
722 // Get Penning rms distance.
723 token = strtok(NULL, " :,%");
724 if (token) {
725 exc.rms = atof(token);
726 // Get decay time.
727 token = strtok(NULL, " :,%");
728 if (token) exc.dt = atof(token);
729 }
730 }
731 excLevels.push_back(std::move(exc));
732 } else if (strcmp(token, "Ionisation") == 0) {
733 // Skip number.
734 token = strtok(NULL, " :,%");
735 // Get label.
736 IonLevel ion;
737 if (quotes) {
738 token = strtok(NULL, "\"");
739 token = strtok(NULL, "\"");
740 } else {
741 token = strtok(NULL, " :,%");
742 }
743 ion.label += token;
744 // Get energy.
745 token = strtok(NULL, " :,%");
746 ion.energy = atof(token);
747 ionLevels.push_back(std::move(ion));
748 }
749 token = strtok(NULL, " :,%");
750 }
751 }
752 return true;
753}

Referenced by LoadGasFile(), and MergeGasFile().

◆ ReadRecord1D()

void Garfield::MediumGas::ReadRecord1D ( std::ifstream &  gasfile,
double &  ve,
double &  vb,
double &  vx,
double &  dl,
double &  dt,
double &  alpha,
double &  alpha0,
double &  eta,
double &  mu,
double &  lor,
double &  dis,
std::array< double, 6 > &  dif,
std::vector< double > &  rexc,
std::vector< double > &  rion 
)
protected

Definition at line 789 of file MediumGas.cc.

793 {
794
795 double waste = 0.;
796 gasfile >> ve >> waste >> vb >> waste >> vx >> waste;
797 ve *= 1.e-3;
798 vb *= 1.e-3;
799 vx *= 1.e-3;
800 gasfile >> dl >> waste >> dt >> waste;
801 gasfile >> alpha >> waste >> alpha0 >> eta >> waste;
802 gasfile >> mu >> waste;
803 mu *= 1.e-3;
804 gasfile >> lor >> waste;
805 gasfile >> dis >> waste;
806 for (int j = 0; j < 6; j++) gasfile >> dif[j] >> waste;
807 const unsigned int nexc = rexc.size();
808 for (unsigned int j = 0; j < nexc; ++j) gasfile >> rexc[j] >> waste;
809 const unsigned int nion = rion.size();
810 for (unsigned int j = 0; j < nion; ++j) gasfile >> rion[j] >> waste;
811}

Referenced by LoadGasFile(), and MergeGasFile().

◆ ReadRecord3D()

void Garfield::MediumGas::ReadRecord3D ( std::ifstream &  gasfile,
double &  ve,
double &  vb,
double &  vx,
double &  dl,
double &  dt,
double &  alpha,
double &  alpha0,
double &  eta,
double &  mu,
double &  lor,
double &  dis,
std::array< double, 6 > &  dif,
std::vector< double > &  rexc,
std::vector< double > &  rion 
)
protected

Definition at line 755 of file MediumGas.cc.

759 {
760
761 // Drift velocity along E, Bt and ExB
762 gasfile >> ve >> vb >> vx;
763 // Convert from cm / us to cm / ns.
764 ve *= 1.e-3;
765 vb *= 1.e-3;
766 vx *= 1.e-3;
767 // Longitudinal and transverse diffusion coefficients
768 gasfile >> dl >> dt;
769 // Townsend and attachment coefficients
770 gasfile >> alpha >> alpha0 >> eta;
771 // Ion mobility
772 gasfile >> mu;
773 // Convert from cm2 / (V us) to cm2 / (V ns)
774 mu *= 1.e-3;
775 // Lorentz angle
776 gasfile >> lor;
777 // Ion dissociation
778 gasfile >> dis;
779 // Diffusion tensor
780 for (int l = 0; l < 6; l++) gasfile >> dif[l];
781 // Excitation rates
782 const unsigned int nexc = rexc.size();
783 for (unsigned int l = 0; l < nexc; ++l) gasfile >> rexc[l];
784 // Ionization rates
785 const unsigned int nion = rion.size();
786 for (unsigned int l = 0; l < nion; ++l) gasfile >> rion[l];
787}

Referenced by LoadGasFile(), and MergeGasFile().

◆ ResetTables()

void Garfield::MediumGas::ResetTables ( )
overridevirtual

Reset all tables of transport parameters.

Reimplemented from Garfield::Medium.

Definition at line 2311 of file MediumGas.cc.

2311 {
2312
2314 m_eAlp0.clear();
2315 m_excLevels.clear();
2316 m_ionLevels.clear();
2317 m_excRates.clear();
2318 m_ionRates.clear();
2319}
virtual void ResetTables()
Reset all tables of transport parameters.
Definition: Medium.cc:905

Referenced by LoadGasFile(), MergeGasFile(), and SetComposition().

◆ ScaleAttachment()

double Garfield::MediumGas::ScaleAttachment ( const double  eta) const
inlineoverridevirtual

Reimplemented from Garfield::Medium.

Definition at line 115 of file MediumGas.hh.

115 {
116 return eta * m_pressure / m_pressureTable;
117 }

◆ ScaleDiffusion()

double Garfield::MediumGas::ScaleDiffusion ( const double  d) const
inlineoverridevirtual

Reimplemented from Garfield::Medium.

Definition at line 106 of file MediumGas.hh.

106 {
107 return d * sqrt(m_pressureTable / m_pressure);
108 }

◆ ScaleDiffusionTensor()

double Garfield::MediumGas::ScaleDiffusionTensor ( const double  d) const
inlineoverridevirtual

Reimplemented from Garfield::Medium.

Definition at line 109 of file MediumGas.hh.

109 {
110 return d * m_pressureTable / m_pressure;
111 }

◆ ScaleElectricField()

double Garfield::MediumGas::ScaleElectricField ( const double  e) const
inlineoverridevirtual

Reimplemented from Garfield::Medium.

Definition at line 100 of file MediumGas.hh.

100 {
101 return e * m_pressureTable / m_pressure;
102 }

◆ ScaleLorentzAngle()

double Garfield::MediumGas::ScaleLorentzAngle ( const double  lor) const
inlineoverridevirtual

Reimplemented from Garfield::Medium.

Definition at line 118 of file MediumGas.hh.

118 {
119 return lor * m_pressure / m_pressureTable;
120 }

◆ ScaleTownsend()

double Garfield::MediumGas::ScaleTownsend ( const double  alpha) const
inlineoverridevirtual

Reimplemented from Garfield::Medium.

Definition at line 112 of file MediumGas.hh.

112 {
114 }

◆ SetAtomicNumber()

void Garfield::MediumGas::SetAtomicNumber ( const double  z)
overridevirtual

Set the effective atomic number.

Reimplemented from Garfield::Medium.

Definition at line 259 of file MediumGas.cc.

259 {
260 std::cerr << m_className << "::SetAtomicNumber:\n"
261 << " Effective Z cannot be changed directly to " << z << ".\n"
262 << " Use SetComposition to define the gas mixture.\n";
263}

◆ SetAtomicWeight()

void Garfield::MediumGas::SetAtomicWeight ( const double  a)
overridevirtual

Set the effective atomic weight.

Reimplemented from Garfield::Medium.

Definition at line 265 of file MediumGas.cc.

265 {
266 std::cerr << m_className << "::SetAtomicWeight:\n"
267 << " Effective A cannot be changed directly to " << a << ".\n"
268 << " Use SetComposition to define the gas mixture.\n";
269}

◆ SetComposition()

bool Garfield::MediumGas::SetComposition ( const std::string &  gas1,
const double  f1 = 1.,
const std::string &  gas2 = "",
const double  f2 = 0.,
const std::string &  gas3 = "",
const double  f3 = 0.,
const std::string &  gas4 = "",
const double  f4 = 0.,
const std::string &  gas5 = "",
const double  f5 = 0.,
const std::string &  gas6 = "",
const double  f6 = 0. 
)

Set the gas mixture.

Definition at line 134 of file MediumGas.cc.

139 {
140 std::array<std::string, 6> gases = {gas1, gas2, gas3, gas4, gas5, gas6};
141 std::array<double, 6> fractions = {f1, f2, f3, f4, f5, f6};
142
143 // Make a backup copy of the gas composition.
144 const std::array<std::string, m_nMaxGases> gasOld = m_gas;
145 const unsigned int nComponentsOld = m_nComponents;
146
147 // Reset all transport parameters.
148 ResetTables();
149 // Force a recalculation of the collision rates.
150 m_isChanged = true;
151
152 m_nComponents = 0;
153 m_gas.fill("");
154 m_fraction.fill(0.);
155 m_atWeight.fill(0.);
156 m_atNum.fill(0.);
157 for (unsigned int i = 0; i < 6; ++i) {
158 if (fractions[i] < Small) continue;
159 // Find the gas name corresponding to the input string.
160 const std::string gasname = GetGasName(gases[i]);
161 if (!gasname.empty()) {
162 m_gas[m_nComponents] = gasname;
163 m_fraction[m_nComponents] = fractions[i];
165 }
166 }
167
168 // Check if at least one valid ingredient was specified.
169 if (m_nComponents == 0) {
170 std::cerr << m_className << "::SetComposition:\n"
171 << " Error setting the composition. No valid components.\n";
172 return false;
173 }
174
175 // Establish the name.
176 m_name = "";
177 double sum = 0.;
178 for (unsigned int i = 0; i < m_nComponents; ++i) {
179 if (i > 0) m_name += "/";
180 m_name += m_gas[i];
181 sum += m_fraction[i];
182 }
183 // Normalise the fractions to one.
184 for (unsigned int i = 0; i < m_nComponents; ++i) {
185 m_fraction[i] /= sum;
186 }
187
188 // Set the atomic weight and number.
189 for (unsigned int i = 0; i < m_nComponents; ++i) {
191 }
192
193 // Print the composition.
194 std::cout << m_className << "::SetComposition:\n " << m_name;
195 if (m_nComponents > 1) {
196 std::cout << " (" << m_fraction[0] * 100;
197 for (unsigned int i = 1; i < m_nComponents; ++i) {
198 std::cout << "/" << m_fraction[i] * 100;
199 }
200 std::cout << ")";
201 }
202 std::cout << "\n";
203
204
205 // Copy the previous Penning transfer parameters.
206 std::array<double, m_nMaxGases> rPenningGasOld;
207 std::array<double, m_nMaxGases> lambdaPenningGasOld;
208 rPenningGasOld.fill(0.);
209 lambdaPenningGasOld.fill(0.);
210 rPenningGasOld.swap(m_rPenningGas);
211 lambdaPenningGasOld.swap(m_lambdaPenningGas);
212 for (unsigned int i = 0; i < m_nComponents; ++i) {
213 for (unsigned int j = 0; j < nComponentsOld; ++j) {
214 if (m_gas[i] != gasOld[j]) continue;
215 if (rPenningGasOld[j] < Small) continue;
216 m_rPenningGas[i] = rPenningGasOld[j];
217 m_lambdaPenningGas[i] = lambdaPenningGasOld[i];
218 std::cout << m_className << "::SetComposition:\n"
219 << " Using Penning transfer parameters for " << m_gas[i]
220 << " from previous mixture.\n"
221 << " r = " << m_rPenningGas[i] << "\n"
222 << " lambda = " << m_lambdaPenningGas[i] << " cm\n";
223 }
224 }
225 return true;
226}

Referenced by GarfieldPhysics::InitializePhysics(), and main().

◆ SetExtrapolationMethodExcitationRates()

void Garfield::MediumGas::SetExtrapolationMethodExcitationRates ( const std::string &  low,
const std::string &  high 
)
inline

Definition at line 83 of file MediumGas.hh.

84 {
85 SetExtrapolationMethod(low, high, m_extrExc, "ExcitationRates");
86 }
void SetExtrapolationMethod(const std::string &low, const std::string &high, std::pair< unsigned int, unsigned int > &extr, const std::string &fcn)
Definition: Medium.cc:1107

◆ SetExtrapolationMethodIonisationRates()

void Garfield::MediumGas::SetExtrapolationMethodIonisationRates ( const std::string &  low,
const std::string &  high 
)
inline

Definition at line 87 of file MediumGas.hh.

88 {
89 SetExtrapolationMethod(low, high, m_extrIon, "IonisationRates");
90 }

◆ SetInterpolationMethodExcitationRates()

void Garfield::MediumGas::SetInterpolationMethodExcitationRates ( const unsigned int  intrp)
inline

Definition at line 91 of file MediumGas.hh.

91 {
92 if (intrp > 0) m_intpExc = intrp;
93 }

◆ SetInterpolationMethodIonisationRates()

void Garfield::MediumGas::SetInterpolationMethodIonisationRates ( const unsigned int  intrp)
inline

Definition at line 94 of file MediumGas.hh.

94 {
95 if (intrp > 0) m_intpIon = intrp;
96 }

◆ SetMassDensity()

void Garfield::MediumGas::SetMassDensity ( const double  rho)
overridevirtual

Set the mass density [g/cm3].

Reimplemented from Garfield::Medium.

Definition at line 277 of file MediumGas.cc.

277 {
278 std::cerr << m_className << "::SetMassDensity:\n"
279 << " Density cannot directly be changed to " << rho << ".\n"
280 << " Use SetTemperature, SetPressure and SetComposition.\n";
281}

◆ SetNumberDensity()

void Garfield::MediumGas::SetNumberDensity ( const double  n)
overridevirtual

Set the number density [cm-3].

Reimplemented from Garfield::Medium.

Definition at line 271 of file MediumGas.cc.

271 {
272 std::cerr << m_className << "::SetNumberDensity:\n"
273 << " Density cannot directly be changed to " << n << ".\n"
274 << " Use SetTemperature and SetPressure.\n";
275}

◆ UnScaleElectricField()

double Garfield::MediumGas::UnScaleElectricField ( const double  e) const
inlineoverridevirtual

Reimplemented from Garfield::Medium.

Definition at line 103 of file MediumGas.hh.

103 {
104 return e * m_pressure / m_pressureTable;
105 }

◆ WriteGasFile()

bool Garfield::MediumGas::WriteGasFile ( const std::string &  filename)

Save the present table of gas properties (transport parameters) to a file.

Definition at line 1755 of file MediumGas.cc.

1755 {
1756
1757 // -----------------------------------------------------------------------
1758 // GASWRT
1759 // -----------------------------------------------------------------------
1760
1761 // Set the gas mixture.
1762 constexpr int nMagboltzGases = 60;
1763 std::vector<double> mixture(nMagboltzGases, 0.);
1764 for (unsigned int i = 0; i < m_nComponents; ++i) {
1765 const int ng = GetGasNumberGasFile(m_gas[i]);
1766 if (ng <= 0) {
1767 std::cerr << m_className << "::WriteGasFile:\n"
1768 << " Error retrieving gas number for " << m_gas[i] << ".\n";
1769 continue;
1770 }
1771 mixture[ng - 1] = m_fraction[i] * 100.;
1772 }
1773
1774 if (m_debug) {
1775 std::cout << m_className << "::WriteGasFile:\n"
1776 << " Writing gas tables to file " << filename << "\n";
1777 }
1778
1779 std::ofstream outfile;
1780 outfile.open(filename.c_str(), std::ios::out);
1781 if (!outfile.is_open()) {
1782 std::cerr << m_className << "::WriteGasFile:\n"
1783 << " Cannot open file " << filename << ".\n";
1784 outfile.close();
1785 return false;
1786 }
1787
1788 // Assemble the GASOK bits.
1789 std::bitset<20> gasok;
1790 GetGasBits(gasok);
1791 std::string okstr(20, 'F');
1792 for (unsigned int i = 0; i < 20; ++i) {
1793 if (gasok[i]) okstr[i] = 'T';
1794 }
1795 if (m_debug) std::cout << " GASOK bits: " << okstr << "\n";
1796 // Get the current time.
1797 time_t rawtime = time(0);
1798 tm timeinfo = *localtime(&rawtime);
1799 char datebuf[80] = {0};
1800 char timebuf[80] = {0};
1801 // Format date and time.
1802 strftime(datebuf, sizeof(datebuf) - 1, "%d/%m/%y", &timeinfo);
1803 strftime(timebuf, sizeof(timebuf) - 1, "%H.%M.%S", &timeinfo);
1804 // Set the member name.
1805 std::string member = "< none >";
1806 // Write the header.
1807 outfile << "*----.----1----.----2----.----3----.----4----.----"
1808 << "5----.----6----.----7----.----8----.----9----.---"
1809 << "10----.---11----.---12----.---13--\n";
1810 outfile << "% Created " << datebuf << " at " << timebuf << " ";
1811 outfile << member << " GAS ";
1812 // Add remark.
1813 std::string buffer;
1814 outfile << "\"none" << std::string(25, ' ') << "\"\n";
1815 const int version = 12;
1816 outfile << " Version : " << version << "\n";
1817 outfile << " GASOK bits: " << okstr << "\n";
1818 std::stringstream ids;
1819 ids.str("");
1820 for (unsigned int i = 0; i < m_nComponents; ++i) {
1821 ids << m_gas[i] << " " << 100. * m_fraction[i] << "%, ";
1822 }
1823 ids << "T=" << m_temperatureTable << " K, "
1824 << "p=" << m_pressureTable / AtmosphericPressure << " atm";
1825 outfile << " Identifier: " << std::setw(80) << std::left << ids.str() << "\n";
1826 outfile << " Clusters : " << std::string(80, ' ') << "\n";
1827 outfile << " Dimension : ";
1828 if (m_tab2d) {
1829 outfile << "T ";
1830 } else {
1831 outfile << "F ";
1832 }
1833
1834 const unsigned int nE = m_eFields.size();
1835 const unsigned int nB = m_bFields.size();
1836 const unsigned int nA = m_bAngles.size();
1837 if (m_debug) {
1838 std::cout << m_className << "::WriteGasFile:\n "
1839 << "Dataset has the following dimensions:\n "
1840 << "3D = " << m_tab2d << " nE = " << nE << ", nB = " << nB
1841 << ", nA = " << nA << ", nExc = "
1842 << m_excLevels.size() << ", nIon = " << m_ionLevels.size() << "\n";
1843 }
1844 outfile << FmtInt(nE, 9) << " " << FmtInt(nA, 9) << " "
1845 << FmtInt(nB, 9) << " " << FmtInt(m_excLevels.size(), 9) << " "
1846 << FmtInt(m_ionLevels.size(), 9) << "\n";
1847 // Store reduced electric fields (E/p).
1848 outfile << " E fields \n";
1849 std::vector<double> efields = m_eFields;
1850 for (auto& field : efields) field /= m_pressureTable;
1851 int cnt = 0;
1852 // List 5 values, then new line.
1853 PrintArray(efields, outfile, cnt, 5);
1854 if (nE % 5 != 0) outfile << "\n";
1855 // Store angles.
1856 outfile << " E-B angles \n";
1857 cnt = 0;
1858 PrintArray(m_bAngles, outfile, cnt, 5);
1859 if (nA % 5 != 0) outfile << "\n";
1860 // Store B fields (convert to hGauss).
1861 outfile << " B fields \n";
1862 std::vector<double> bfields = m_bFields;
1863 for (auto& field : bfields) field *= 100.;
1864 cnt = 0;
1865 PrintArray(bfields, outfile, cnt, 5);
1866 if (nB % 5 != 0) outfile << "\n";
1867
1868 // Store the gas composition.
1869 outfile << " Mixture: \n";
1870 cnt = 0;
1871 PrintArray(mixture, outfile, cnt, 5);
1872 if (nMagboltzGases % 5 != 0) outfile << "\n";
1873
1874 cnt = 0;
1875 for (const auto& exc : m_excLevels) {
1876 ++cnt;
1877 outfile << " Excitation " << FmtInt(cnt, 5) << ": " << std::setw(45);
1878 // If the label contains white space, enclose it in quotes.
1879 if (exc.label.find(" ") != std::string::npos) {
1880 outfile << "\"" + exc.label + "\"";
1881 } else {
1882 outfile << exc.label;
1883 }
1884 outfile << " " << FmtFloat(exc.energy) << FmtFloat(exc.prob)
1885 << FmtFloat(exc.rms) << FmtFloat(exc.dt) << "\n";
1886 }
1887 cnt = 0;
1888 for (const auto& ion : m_ionLevels) {
1889 ++cnt;
1890 outfile << " Ionisation " << FmtInt(cnt, 5) << ": " << std::setw(45);
1891 // If the label contains white space, enclose it in quotes.
1892 if (ion.label.find(" ") != std::string::npos) {
1893 outfile << "\"" + ion.label << "\"";
1894 } else {
1895 outfile << ion.label;
1896 }
1897 outfile << " " << FmtFloat(ion.energy) << "\n";
1898 }
1899
1900 const double sqrp = sqrt(m_pressureTable);
1901 const double logp = log(m_pressureTable);
1902 outfile << " The gas tables follow:\n";
1903 cnt = 0;
1904 for (unsigned int i = 0; i < nE; ++i) {
1905 for (unsigned int j = 0; j < nA; ++j) {
1906 for (unsigned int k = 0; k < nB; ++k) {
1907 // Get the velocities.
1908 double ve = m_eVelE.empty() ? 0. : m_eVelE[j][k][i];
1909 double vb = m_eVelB.empty() ? 0. : m_eVelB[j][k][i];
1910 double vx = m_eVelX.empty() ? 0. : m_eVelX[j][k][i];
1911 // Convert from cm / ns to cm / us.
1912 ve *= 1.e3;
1913 vb *= 1.e3;
1914 vx *= 1.e3;
1915 // Make a list of the values to be written, start with the velocities.
1916 std::vector<double> val;
1917 if (m_tab2d) {
1918 val = {ve, vb, vx};
1919 } else {
1920 // Add dummy spline values in case of a 1D table.
1921 val = {ve, 0., vb, 0., vx, 0.};
1922 }
1923 // Get the diffusion coefficients.
1924 double dl = m_eDifL.empty() ? 0. : m_eDifL[j][k][i] * sqrp;
1925 double dt = m_eDifT.empty() ? 0. : m_eDifT[j][k][i] * sqrp;
1926 // Get the Townsend and attachment coefficients.
1927 double alpha = m_eAlp.empty() ? -30. : m_eAlp[j][k][i] - logp;
1928 double alpha0 = m_eAlp0.empty() ? -30. : m_eAlp0[j][k][i] - logp;
1929 double eta = m_eAtt.empty() ? -30. : m_eAtt[j][k][i] - logp;
1930 // Add them to the list.
1931 if (m_tab2d) {
1932 val.insert(val.end(), {dl, dt, alpha, alpha0, eta});
1933 } else {
1934 val.insert(val.end(), {dl, 0., dt, 0., alpha, 0., alpha0, eta, 0.});
1935 }
1936 // Get the ion mobility and convert from cm2 / (V ns) to cm2 / (V us).
1937 double mu = m_iMob.empty() ? 0. : 1.e3 * m_iMob[j][k][i];
1938 // Get the Lorentz angle.
1939 double lor = m_eLor.empty() ? 0 : m_eLor[j][k][i];
1940 // Get the dissociation coefficient.
1941 double diss = m_iDis.empty() ? -30. : m_iDis[j][k][i] - logp;
1942 // Add them to the list.
1943 if (m_tab2d) {
1944 val.insert(val.end(), {mu, lor, diss});
1945 } else {
1946 val.insert(val.end(), {mu, 0., lor, 0., diss, 0.});
1947 }
1948 // Get the components of the diffusion tensor.
1949 for (int l = 0; l < 6; ++l) {
1950 if (!m_eDifM.empty()) {
1951 const double cov = m_eDifM[l][j][k][i] * m_pressureTable;
1952 val.push_back(cov);
1953 } else {
1954 val.push_back(0.);
1955 }
1956 if (!m_tab2d) val.push_back(0.);
1957 }
1958 // Get the excitation and ionisation rates.
1959 for (const auto& rexc : m_excRates) {
1960 if (rexc[j][k][i] > Small) {
1961 val.push_back(rexc[j][k][i]);
1962 } else {
1963 val.push_back(0.);
1964 }
1965 if (!m_tab2d) val.push_back(0.);
1966 }
1967 for (const auto& rion : m_ionRates) {
1968 if (rion[j][k][i] > Small) {
1969 val.push_back(rion[j][k][i]);
1970 } else {
1971 val.push_back(0.);
1972 }
1973 if (!m_tab2d) val.push_back(0.);
1974 }
1975 PrintArray(val, outfile, cnt, 8);
1976 }
1977 if (cnt % 8 != 0) outfile << "\n";
1978 cnt = 0;
1979 }
1980 }
1981
1982 if (!m_tab2d) {
1983 // Extrapolation methods
1984 int extrapH[13], extrapL[13];
1985 extrapL[0] = extrapL[1] = extrapL[2] = m_extrVel.first;
1986 extrapH[0] = extrapH[1] = extrapH[2] = m_extrVel.second;
1987 extrapL[3] = extrapL[8] = extrapL[10] = m_extrDif.first;
1988 extrapH[3] = extrapH[8] = extrapH[10] = m_extrDif.second;
1989 extrapL[4] = m_extrAlp.first;
1990 extrapH[4] = m_extrAlp.second;
1991 extrapL[5] = m_extrAtt.first;
1992 extrapH[5] = m_extrAtt.second;
1993 extrapL[6] = m_extrMob.first;
1994 extrapH[6] = m_extrMob.second;
1995 // Lorentz angle
1996 extrapL[7] = m_extrLor.first;
1997 extrapH[7] = m_extrLor.second;
1998 extrapL[9] = m_extrDis.first;
1999 extrapH[9] = m_extrDis.second;
2000 extrapL[11] = m_extrExc.first;
2001 extrapH[11] = m_extrExc.second;
2002 extrapL[12] = m_extrIon.first;
2003 extrapH[12] = m_extrIon.second;
2004 outfile << " H Extr: ";
2005 for (int i = 0; i < 13; i++) outfile << FmtInt(extrapH[i], 5);
2006 outfile << "\n";
2007 outfile << " L Extr: ";
2008 for (int i = 0; i < 13; i++) outfile << FmtInt(extrapL[i], 5);
2009 outfile << "\n";
2010 }
2011 // Increment the threshold indices for compatibility with Fortran.
2012 outfile << " Thresholds: " << FmtInt(m_eThrAlp + 1, 10)
2013 << FmtInt(m_eThrAtt + 1, 10) << FmtInt(m_iThrDis + 1, 10) << "\n";
2014 // Interpolation methods.
2015 int interp[13];
2016 interp[0] = interp[1] = interp[2] = m_intpVel;
2017 interp[3] = interp[8] = interp[10] = m_intpDif;
2018 interp[4] = m_intpAlp;
2019 interp[5] = m_intpAtt;
2020 interp[6] = m_intpMob;
2021 interp[7] = m_intpLor;
2022 interp[9] = m_intpDis;
2023 interp[11] = m_intpExc;
2024 interp[12] = m_intpIon;
2025 outfile << " Interp: ";
2026 for (int i = 0; i < 13; i++) outfile << FmtInt(interp[i], 5);
2027 outfile << "\n";
2028 outfile << " A =" << FmtFloat(0.) << ", Z =" << FmtFloat(0.) << ","
2029 << " EMPROB=" << FmtFloat(0.) << ", EPAIR =" << FmtFloat(0.) << "\n";
2030 const double dli = m_iDifL.empty() ? 0. : m_iDifL[0][0][0];
2031 const double dti = m_iDifT.empty() ? 0. : m_iDifT[0][0][0];
2032 outfile << " Ion diffusion: " << FmtFloat(dli) << FmtFloat(dti) << "\n";
2033 outfile << " CMEAN =" << FmtFloat(0.) << ", RHO =" << FmtFloat(0.) << ","
2034 << " PGAS =" << FmtFloat(m_pressureTable) << ","
2035 << " TGAS =" << FmtFloat(m_temperatureTable) << "\n";
2036 outfile << " CLSTYP : NOT SET \n"
2037 << " FCNCLS : " << std::string(80, ' ') << "\n"
2038 << " NCLS : " << FmtInt(0, 10) << "\n"
2039 << " Average : " << FmtFloat(0., 25, 18) << "\n"
2040 << " Heed initialisation done: F\n"
2041 << " SRIM initialisation done: F\n";
2042 outfile.close();
2043
2044 return true;
2045}
int GetGasNumberGasFile(const std::string &input) const
Definition: MediumGas.cc:3140

◆ ZeroRowA()

void Garfield::MediumGas::ZeroRowA ( const int  ia,
const int  ne,
const int  nb 
)
protected

Definition at line 1747 of file MediumGas.cc.

1747 {
1748 for (int j = 0; j < nb; ++j) {
1749 for (int i = 0; i < ne; ++i) {
1750 if (!m_eVelE.empty()) m_eVelE[ia][j][i] = 0.;
1751 }
1752 }
1753}

Referenced by MergeGasFile().

◆ ZeroRowB()

void Garfield::MediumGas::ZeroRowB ( const int  ib,
const int  ne,
const int  na 
)
protected

Definition at line 1739 of file MediumGas.cc.

1739 {
1740 for (int k = 0; k < na; ++k) {
1741 for (int i = 0; i < ne; ++i) {
1742 if (!m_eVelE.empty()) m_eVelE[k][ib][i] = 0.;
1743 }
1744 }
1745}

Referenced by MergeGasFile().

◆ ZeroRowE()

void Garfield::MediumGas::ZeroRowE ( const int  ie,
const int  nb,
const int  na 
)
protected

Definition at line 1731 of file MediumGas.cc.

1731 {
1732 for (int k = 0; k < na; ++k) {
1733 for (int j = 0; j < nb; ++j) {
1734 if (!m_eVelE.empty()) m_eVelE[k][j][ie] = 0.;
1735 }
1736 }
1737}

Referenced by MergeGasFile().

Member Data Documentation

◆ m_atNum

std::array<double, m_nMaxGases> Garfield::MediumGas::m_atNum
protected

Definition at line 132 of file MediumGas.hh.

Referenced by GetAtomicNumber(), LoadGasFile(), MediumGas(), and SetComposition().

◆ m_atWeight

std::array<double, m_nMaxGases> Garfield::MediumGas::m_atWeight
protected

Definition at line 131 of file MediumGas.hh.

Referenced by GetAtomicWeight(), LoadGasFile(), MediumGas(), and SetComposition().

◆ m_eAlp0

std::vector<std::vector<std::vector<double> > > Garfield::MediumGas::m_eAlp0
protected

◆ m_excLevels

◆ m_excRates

std::vector<std::vector<std::vector<std::vector<double> > > > Garfield::MediumGas::m_excRates
protected

◆ m_extrExc

std::pair<unsigned int, unsigned int> Garfield::MediumGas::m_extrExc = {0, 1}
protected

◆ m_extrIon

std::pair<unsigned int, unsigned int> Garfield::MediumGas::m_extrIon = {0, 1}
protected

◆ m_fraction

◆ m_gas

◆ m_intpExc

unsigned int Garfield::MediumGas::m_intpExc = 2
protected

◆ m_intpIon

unsigned int Garfield::MediumGas::m_intpIon = 2
protected

◆ m_ionLevels

std::vector<IonLevel> Garfield::MediumGas::m_ionLevels
protected

◆ m_ionRates

std::vector<std::vector<std::vector<std::vector<double> > > > Garfield::MediumGas::m_ionRates
protected

◆ m_lambdaPenningGas

std::array<double, m_nMaxGases> Garfield::MediumGas::m_lambdaPenningGas
protected

◆ m_lambdaPenningGlobal

double Garfield::MediumGas::m_lambdaPenningGlobal = 0.
protected

◆ m_nMaxGases

constexpr unsigned int Garfield::MediumGas::m_nMaxGases = 6
staticconstexprprotected

Definition at line 126 of file MediumGas.hh.

Referenced by GetMixture(), and GetPhotoAbsorptionCrossSection().

◆ m_pressureTable

◆ m_rPenningGas

std::array<double, m_nMaxGases> Garfield::MediumGas::m_rPenningGas
protected

◆ m_rPenningGlobal

double Garfield::MediumGas::m_rPenningGlobal = 0.
protected

◆ m_temperatureTable

double Garfield::MediumGas::m_temperatureTable
protected

◆ m_usePenning


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