20std::string FmtFloat(
const double x,
const unsigned int width = 15,
21 const unsigned int precision = 8) {
23 std::snprintf(buffer, width + 1,
"%*.*E", width, precision, x);
24 return std::string(buffer);
27std::string FmtInt(
const int n,
const unsigned int width) {
29 std::snprintf(buffer, width + 1,
"%*d", width, n);
30 return std::string(buffer);
33void PrintArray(
const std::vector<double>& values, std::ofstream& outfile,
34 int& col,
const int ncols) {
35 for (
const auto value : values) {
36 outfile << FmtFloat(value);
38 if (col % ncols == 0) outfile <<
"\n";
42void PrintExtrapolation(
const std::pair<unsigned int, unsigned int>& extr) {
43 std::cout <<
" Low field extrapolation: ";
45 std::cout <<
" constant\n";
46 else if (extr.first == 1)
47 std::cout <<
" linear\n";
48 else if (extr.first == 2)
49 std::cout <<
" exponential\n";
51 std::cout <<
" unknown\n";
52 std::cout <<
" High field extrapolation: ";
54 std::cout <<
" constant\n";
55 else if (extr.second == 1)
56 std::cout <<
" linear\n";
57 else if (extr.second == 2)
58 std::cout <<
" exponential\n";
60 std::cout <<
" unknown\n";
63void PrintAbsentInNew(
const std::string& par) {
64 std::cout <<
" Warning: The " << par <<
" is absent in the dataset "
65 <<
"to be added; data reset.\n";
68void PrintAbsentInExisting(
const std::string& par) {
69 std::cout <<
" Warning: The " << par <<
" is absent in the existing data; "
70 <<
"new data not used.\n";
73bool Similar(
const double v1,
const double v2,
const double eps) {
74 const double dif = v1 - v2;
75 const double sum =
fabs(v1) +
fabs(v2);
76 return fabs(dif) < std::max(eps * sum, Garfield::Small);
79int Equal(
const std::vector<double>& fields1,
80 const std::vector<double>& fields2,
const double eps) {
81 if (fields1.size() != fields2.size())
return 0;
82 const unsigned int n = fields1.size();
83 for (
unsigned int i = 0; i < n; ++i) {
84 if (!Similar(fields1[i], fields2[i], eps))
return 0;
89int FindIndex(
const double field,
const std::vector<double>& fields,
92 const int n = fields.size();
93 for (
int i = 0; i < n; ++i) {
94 if (Similar(field, fields[i], eps))
return i;
99void ResizeA(std::vector<std::vector<std::vector<double> > >& tab,
100 const int ne,
const int nb,
const int na) {
101 if (tab.empty())
return;
103 std::vector<std::vector<double> >(nb,
104 std::vector<double>(ne, 0.)));
112 :
Medium(), m_pressureTable(m_pressure), m_temperatureTable(m_temperature) {
135 const std::string& gas2,
const double f2,
136 const std::string& gas3,
const double f3,
137 const std::string& gas4,
const double f4,
138 const std::string& gas5,
const double f5,
139 const std::string& gas6,
const double f6) {
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};
144 const std::array<std::string, m_nMaxGases> gasOld =
m_gas;
157 for (
unsigned int i = 0; i < 6; ++i) {
158 if (fractions[i] < Small)
continue;
160 const std::string gasname =
GetGasName(gases[i]);
161 if (!gasname.empty()) {
171 <<
" Error setting the composition. No valid components.\n";
206 std::array<double, m_nMaxGases> rPenningGasOld;
207 std::array<double, m_nMaxGases> lambdaPenningGasOld;
208 rPenningGasOld.fill(0.);
209 lambdaPenningGasOld.fill(0.);
213 for (
unsigned int j = 0; j < nComponentsOld; ++j) {
214 if (
m_gas[i] != gasOld[j])
continue;
215 if (rPenningGasOld[j] < Small)
continue;
219 <<
" Using Penning transfer parameters for " <<
m_gas[i]
220 <<
" from previous mixture.\n"
229 double& f2, std::string& gas3,
double& f3,
230 std::string& gas4,
double& f4, std::string& gas5,
231 double& f5, std::string& gas6,
double& f6) {
249 std::cerr <<
m_className <<
"::GetComponent: Index out of range.\n";
261 <<
" Effective Z cannot be changed directly to " << z <<
".\n"
262 <<
" Use SetComposition to define the gas mixture.\n";
267 <<
" Effective A cannot be changed directly to " << a <<
".\n"
268 <<
" Use SetComposition to define the gas mixture.\n";
272 std::cerr <<
m_className <<
"::SetNumberDensity:\n"
273 <<
" Density cannot directly be changed to " << n <<
".\n"
274 <<
" Use SetTemperature and SetPressure.\n";
279 <<
" Density cannot directly be changed to " << rho <<
".\n"
280 <<
" Use SetTemperature, SetPressure and SetComposition.\n";
294 return LoschmidtNumber * (
m_pressure / AtmosphericPressure) *
317 std::ifstream gasfile;
319 gasfile.open(filename.c_str());
321 if (!gasfile.is_open()) {
323 <<
" Cannot open file " << filename <<
".\n";
326 std::cout <<
m_className <<
"::LoadGasFile: Reading " << filename <<
".\n";
334 std::bitset<20> gasok;
336 constexpr int nMagboltzGases = 60;
337 std::vector<double> mixture(nMagboltzGases, 0.);
343 std::cout <<
m_className <<
"::LoadGasFile: Version " << version <<
"\n";
346 std::vector<std::string> gasnames;
347 std::vector<double> percentages;
348 if (!
GetMixture(mixture, version, gasnames, percentages)) {
350 <<
"Cannot determine the gas composition.\n";
360 m_gas[i] = gasnames[i];
365 <<
" Gas composition set to " <<
m_name;
379 std::cout <<
m_className <<
"::LoadGasFile:\n " << nE
380 <<
" electric field(s), " << nB
381 <<
" magnetic field(s), " << nA <<
" angle(s).\n";
416 if (gasok[11])
Init(nE, nB, nA,
m_iDis, -30.);
424 const std::string fmt =
m_tab2d ?
"3D" :
"1D";
425 std::cout <<
m_className <<
"::LoadGasFile: Reading " << fmt <<
" table.\n";
429 double ve = 0., vb = 0., vx = 0.;
433 double dl = 0., dt = 0.;
435 double alpha = 0., alpha0 = 0., eta = 0.;
437 double mu = 0., dis = 0.;
439 std::array<double, 6> diff;
442 std::vector<double> rexc(nexc, 0.);
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++) {
449 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
450 lor, dis, diff, rexc, rion);
452 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
453 lor, dis, diff, rexc, rion);
469 for (
int l = 0; l < 6; l++) {
474 for (
unsigned int l = 0; l < nexc; ++l) {
479 for (
unsigned int l = 0; l < nion; ++l) {
488 std::array<unsigned int, 13> extrapH = {{0}};
489 std::array<unsigned int, 13> extrapL = {{1}};
491 std::array<unsigned int, 13> interp = {{2}};
493 double ionDiffL = 0.;
494 double ionDiffT = 0.;
499 gasfile.ignore(std::numeric_limits<std::streamsize>::max(),
'\n');
520 for (
int i = nE; i--;) {
521 for (
int j = nA; j--;) {
522 for (
int k = nB; k--;) {
570 if (ionDiffL > 0.)
Init(nE, nB, nA,
m_iDifL, ionDiffL);
571 if (ionDiffT > 0.)
Init(nE, nB, nA,
m_iDifT, ionDiffT);
579 std::bitset<20>& gasok,
bool& is3d, std::vector<double>& mixture,
580 std::vector<double>& efields, std::vector<double>& bfields,
581 std::vector<double>& angles, std::vector<ExcLevel>& excLevels,
582 std::vector<IonLevel>& ionLevels) {
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) {
595 char* token = strtok(line,
" :,%");
597 if (strcmp(token,
"Version") == 0) {
598 token = strtok(NULL,
" :,%");
599 version = atoi(token);
601 if (version != 10 && version != 11 && version != 12) {
603 <<
" The file has version number " << version <<
".\n"
604 <<
" Files written in this format cannot be read.\n";
607 }
else if (strcmp(token,
"GASOK") == 0) {
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) {
616 <<
" Unexpected size of GASOK string ("
617 << okstr.size() <<
").\n";
620 for (
unsigned int i = 0; i < 20; ++i) {
621 if (okstr[i] ==
'T') gasok.set(i);
623 }
else if (strcmp(token,
"Identifier") == 0) {
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) {
636 token = strtok(NULL,
" :,%\t");
637 const int nE = atoi(token);
641 <<
" Number of E fields out of range.\n";
644 token = strtok(NULL,
" :,%\t");
645 const int nA = atoi(token);
647 if (is3d && nA <= 0) {
649 <<
" Number of E-B angles out of range.\n";
652 token = strtok(NULL,
" :,%\t");
653 const int nB = atoi(token);
655 if (is3d && nB <= 0) {
657 <<
" Number of B fields out of range.\n";
665 token = strtok(NULL,
" :,%\t");
666 const int nexc = atoi(token);
668 token = strtok(NULL,
" :,%\t");
669 const int nion = atoi(token);
671 std::cout <<
" " << nexc <<
" excitations, " << nion
672 <<
" ionisations.\n";
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];
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];
686 }
else if (strcmp(token,
"B") == 0) {
687 token = strtok(NULL,
" :,%");
688 if (strncmp(token,
"fields", 6) == 0) {
690 const int nB = bfields.size();
691 for (
int i = 0; i < nB; i++) {
693 bfields[i] = bstore / 100.;
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];
701 }
else if (strcmp(token,
"Excitation") == 0) {
703 token = strtok(NULL,
" :,%");
707 token = strtok(NULL,
"\"");
708 token = strtok(NULL,
"\"");
710 token = strtok(NULL,
" :,%");
714 token = strtok(NULL,
" :,%");
717 token = strtok(NULL,
" :,%");
718 exc.
prob = atof(token);
723 token = strtok(NULL,
" :,%");
725 exc.
rms = atof(token);
727 token = strtok(NULL,
" :,%");
728 if (token) exc.
dt = atof(token);
731 excLevels.push_back(std::move(exc));
732 }
else if (strcmp(token,
"Ionisation") == 0) {
734 token = strtok(NULL,
" :,%");
738 token = strtok(NULL,
"\"");
739 token = strtok(NULL,
"\"");
741 token = strtok(NULL,
" :,%");
745 token = strtok(NULL,
" :,%");
747 ionLevels.push_back(std::move(ion));
749 token = strtok(NULL,
" :,%");
756 double& ve,
double& vb,
double& vx,
double& dl,
double& dt,
757 double& alpha,
double& alpha0,
double& eta,
double& mu,
double& lor,
758 double& dis, std::array<double, 6>& dif,
759 std::vector<double>& rexc, std::vector<double>& rion) {
762 gasfile >> ve >> vb >> vx;
770 gasfile >> alpha >> alpha0 >> eta;
780 for (
int l = 0; l < 6; l++) gasfile >> dif[l];
782 const unsigned int nexc = rexc.size();
783 for (
unsigned int l = 0; l < nexc; ++l) gasfile >> rexc[l];
785 const unsigned int nion = rion.size();
786 for (
unsigned int l = 0; l < nion; ++l) gasfile >> rion[l];
790 double& ve,
double& vb,
double& vx,
double& dl,
double& dt,
791 double& alpha,
double& alpha0,
double& eta,
double& mu,
double& lor,
792 double& dis, std::array<double, 6>& dif,
793 std::vector<double>& rexc, std::vector<double>& rion) {
796 gasfile >> ve >> waste >> vb >> waste >> vx >> waste;
800 gasfile >> dl >> waste >> dt >> waste;
801 gasfile >> alpha >> waste >> alpha0 >> eta >> waste;
802 gasfile >> mu >> waste;
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;
814 std::array<unsigned int, 13>& extrapH,
815 std::array<unsigned int, 13>& extrapL,
816 std::array<unsigned int, 13>& interp,
817 unsigned int& thrAlp,
unsigned int& thrAtt,
unsigned int& thrDis,
818 double& ionDiffL,
double& ionDiffT,
819 double& pgas,
double& tgas) {
824 gasfile.getline(line, 256);
825 char* token = strtok(line,
" :,%=\t");
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);
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);
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);
851 }
else if (strcmp(token,
"A") == 0) {
852 token = strtok(NULL,
" :,%=\t");
856 }
else if (strcmp(token,
"Z") == 0) {
858 token = strtok(NULL,
" :,%=\t");
861 }
else if (strcmp(token,
"EMPROB") == 0) {
863 token = strtok(NULL,
" :,%=\t");
866 }
else if (strcmp(token,
"EPAIR") == 0) {
868 token = strtok(NULL,
" :,%=\t");
871 }
else if (strcmp(token,
"Ion") == 0) {
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) {
880 token = strtok(NULL,
" :,%=\t");
883 }
else if (strcmp(token,
"RHO") == 0) {
885 token = strtok(NULL,
" :,%=\t");
888 }
else if (strcmp(token,
"PGAS") == 0) {
890 token = strtok(NULL,
" :,%=\t");
891 if (token != NULL) pgas = atof(token);
892 }
else if (strcmp(token,
"TGAS") == 0) {
894 token = strtok(NULL,
" :,%=\t");
895 if (token != NULL) tgas = atof(token);
902 token = strtok(NULL,
" :,%=\t");
908 const int version, std::vector<std::string>& gasnames,
909 std::vector<double>& percentages)
const {
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()) {
919 <<
" Unknown gas (gas number " << i + 1 <<
").\n";
922 gasnames.push_back(gasname);
923 percentages.push_back(mixture[i]);
927 <<
" Gas mixture has " << gasnames.size() <<
" components.\n"
928 <<
" Number of gases is limited to " <<
m_nMaxGases <<
".\n";
930 }
else if (gasnames.empty()) {
932 <<
" Gas mixture is not defined (zero components).\n";
935 double sum = std::accumulate(percentages.begin(), percentages.end(), 0.);
938 <<
" Renormalizing the percentages.\n";
939 for (
auto& percentage : percentages) percentage *= 100. / sum;
945 const bool replaceOld) {
952 constexpr double eps = 1.e-3;
954 std::ifstream gasfile;
956 gasfile.open(filename.c_str());
958 if (!gasfile.is_open()) {
960 <<
" Cannot open file " << filename <<
".\n";
965 std::bitset<20> gasok;
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",
983 <<
"This dataset cannot be read because of a change in format.\n";
989 std::vector<std::string> gasnames;
990 std::vector<double> percentages;
991 if (!
GetMixture(mixture, version, gasnames, percentages)) {
993 <<
"Cannot determine the gas composition.\n";
999 <<
"Composition of the dataset differs from the present one.\n";
1005 const auto it = std::find(gasnames.begin(), gasnames.end(),
m_gas[i]);
1006 if (it == gasnames.end()) {
1008 <<
"Composition of the dataset differs from the present one.\n";
1013 const double f1 = 0.01 * percentages[it - gasnames.begin()];
1014 if (fabs(f1 - f2) > 1.e-6 * (1. + fabs(f1) + fabs(f2))) {
1016 <<
"Percentages of " <<
m_gas[i] <<
" differ.\n";
1023 const unsigned int nexc = excLevels.size();
1024 const unsigned int nion = ionLevels.size();
1027 for (
unsigned int i = 0; i < nexc; ++i) {
1028 if (
m_excLevels[i].label == excLevels[i].label)
continue;
1035 for (
unsigned int i = 0; i < nion; ++i) {
1036 if (
m_ionLevels[i].label == ionLevels[i].label)
continue;
1043 double ve = 0., vb = 0., vx = 0.;
1047 double dl = 0., dt = 0.;
1049 double alpha = 0., alpha0 = 0., eta = 0.;
1051 double mu = 0., dis = 0.;
1053 std::array<double, 6> diff;
1055 std::vector<double> rexc(nexc, 0.);
1056 std::vector<double> rion(nion, 0.);
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++) {
1065 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1066 lor, dis, diff, rexc, rion);
1068 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1069 lor, dis, diff, rexc, rion);
1076 std::array<unsigned int, 13> extrapH = {{0}};
1077 std::array<unsigned int, 13> extrapL = {{1}};
1079 std::array<unsigned int, 13> interp = {{2}};
1081 unsigned int thrAlp = 0, thrAtt = 0, thrDis = 0;
1083 double ionDiffL = 0., ionDiffT = 0.;
1085 double pgas = 0., tgas = 0.;
1087 gasfile.ignore(std::numeric_limits<std::streamsize>::max(),
'\n');
1088 ReadFooter(gasfile, extrapH, extrapL, interp, thrAlp, thrAtt, thrDis,
1089 ionDiffL, ionDiffT, pgas, tgas);
1094 <<
"The gas pressure of the dataset to be read differs\n "
1095 <<
"from the current reference pressure; stop.\n";
1101 <<
"The gas temperature of the dataset to be read differs\n "
1102 <<
"from the current reference temperature; stop.\n";
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",
1118 for (
auto& field : efields) field *= pgas;
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";
1132 const int iemode = Equal(efields,
m_eFields, eps);
1134 const int iamode = Equal(angles,
m_bAngles, eps);
1136 const int ibmode = Equal(bfields,
m_bFields, eps);
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";
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";
1154 if ((is3d || ibmode * iamode == 0) && !
m_tab2d) {
1155 if (
m_debug) std::cout <<
" Expanding existing table to 3D mode.\n";
1160 std::bitset<20> existing;
1163 if (iemode * ibmode * iamode == 0) {
1165 if (existing[0] && !gasok[0]) {
1168 PrintAbsentInNew(
"drift velocity");
1170 if (existing[1] && !gasok[1]) {
1173 PrintAbsentInNew(
"ion mobility");
1175 if (existing[2] && !gasok[2]) {
1178 PrintAbsentInNew(
"longitudinal diffusion");
1180 if (existing[3] && !gasok[3]) {
1183 PrintAbsentInNew(
"Townsend coefficient");
1185 if (existing[5] && !gasok[5]) {
1188 PrintAbsentInNew(
"attachment coefficient");
1190 if (existing[6] && !gasok[6]) {
1193 PrintAbsentInNew(
"Lorentz angle");
1195 if (existing[7] && !gasok[7]) {
1198 PrintAbsentInNew(
"transverse diffusion");
1200 if (existing[8] && !gasok[8]) {
1203 PrintAbsentInNew(
"velocity along Bt");
1205 if (existing[9] && !gasok[9]) {
1208 PrintAbsentInNew(
"velocity along ExB");
1210 if (existing[10] && !gasok[10]) {
1213 PrintAbsentInNew(
"diffusion tensor");
1215 if (existing[11] && !gasok[11]) {
1218 PrintAbsentInNew(
"ion dissociation data");
1220 if (existing[14] && !gasok[14]) {
1224 PrintAbsentInNew(
"excitation data");
1226 if (existing[15] && !gasok[15]) {
1230 PrintAbsentInNew(
"ionisation data");
1233 if (!existing[0] && gasok[0]) {
1235 PrintAbsentInExisting(
"drift velocity");
1237 if (!existing[1] && gasok[1]) {
1239 PrintAbsentInExisting(
"ion mobility");
1241 if (!existing[2] && gasok[2]) {
1243 PrintAbsentInExisting(
"longitudinal diffusion");
1245 if (!existing[3] && gasok[3]) {
1247 PrintAbsentInExisting(
"Townsend coefficient");
1249 if (!existing[5] && gasok[5]) {
1251 PrintAbsentInExisting(
"attachment coefficient");
1253 if (!existing[6] && gasok[6]) {
1255 PrintAbsentInExisting(
"Lorentz angle");
1257 if (!existing[7] && gasok[7]) {
1259 PrintAbsentInExisting(
"transverse diffusion");
1261 if (!existing[8] && gasok[8]) {
1263 PrintAbsentInExisting(
"velocity along Bt");
1265 if (!existing[9] && gasok[9]) {
1267 PrintAbsentInExisting(
"velocity along ExB");
1269 if (!existing[10] && gasok[10]) {
1271 PrintAbsentInExisting(
"diffusion tensor");
1273 if (!existing[11] && gasok[11]) {
1275 PrintAbsentInExisting(
"ion dissociation data");
1277 if (!existing[14] && gasok[14]) {
1279 PrintAbsentInExisting(
"excitation data");
1281 if (!existing[15] && gasok[15]) {
1283 PrintAbsentInExisting(
"ionisation data");
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";
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";
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]) {
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)) {
1323 if (gasok[15] && (!existing[15] || replaceOld)) {
1329 std::vector<bool> newE(nE,
false);
1330 std::vector<bool> newA(nA,
false);
1331 std::vector<bool> newB(nB,
false);
1333 std::cout <<
m_className <<
"::MergeGasFile: Extending the tables.\n";
1337 for (
const auto efield : efields) {
1340 for (
unsigned int j = 0; j < nE; ++j) {
1342 if (Similar(efield,
m_eFields[j], eps)) {
1344 std::cout <<
" Replacing existing data for E = "
1345 <<
m_eFields[j] <<
" V/cm by data from file.\n";
1350 std::cout <<
" Keeping existing data for E = " <<
m_eFields[j]
1351 <<
" V/cm, not using data from the file.\n";
1358 std::cout <<
" Inserting E = " << efield
1359 <<
" V/cm at slot " << j <<
".\n";
1363 newE.insert(newE.begin() + j,
true);
1370 if (found)
continue;
1373 std::cout <<
" Adding E = " << efield <<
" V/cm at the end.\n";
1377 newE.push_back(
true);
1385 for (
const auto bfield : bfields) {
1388 for (
unsigned int j = 0; j < nB; ++j) {
1390 if (Similar(bfield,
m_bFields[j], eps)) {
1392 std::cout <<
" Replacing old data for B = " <<
m_bFields[j]
1393 <<
" T by data from file.\n";
1398 std::cout <<
" Keeping old data for B = " <<
m_bFields[j]
1399 <<
" T, not using data from file.\n";
1406 std::cout <<
" Inserting B = " << bfield <<
" T at slot "
1411 newB.insert(newB.begin() + j,
true);
1418 if (found)
continue;
1421 std::cout <<
" Adding B = " << bfield <<
" T at the end.\n";
1425 newB.push_back(
true);
1433 for (
const auto angle : angles) {
1436 for (
unsigned int j = 0; j < nA; ++j) {
1438 if (Similar(angle,
m_bAngles[j], eps)) {
1440 std::cout <<
" Replacing old data for angle(E,B) = "
1442 <<
" degrees by data from the file.\n";
1447 std::cout <<
" Keeping old data for angle(E,B) = "
1449 <<
" degrees, not using data from file.\n";
1456 std::cout <<
" Inserting angle = " << angle * RadToDegree
1457 <<
" degrees at slot " << j <<
".\n";
1461 newA.insert(newA.begin() + j,
true);
1468 if (found)
continue;
1471 std::cout <<
" Adding angle = " << angle * RadToDegree
1472 <<
" degrees at the end.\n";
1476 newA.push_back(
true);
1482 const double sqrp = sqrt(pgas);
1483 const double logp = log(pgas);
1486 for (
const auto efield : efields) {
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) {
1494 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1495 lor, dis, diff, rexc, rion);
1497 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1498 lor, dis, diff, rexc, rion);
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";
1509 const bool update = newE[inde] || newA[inda] || newB[indb] || replaceOld;
1511 if (gasok[0] && (update || !existing[0])) {
1512 m_eVelE[inda][indb][inde] = ve;
1514 if (gasok[1] && (update || !existing[1])) {
1515 m_iMob[inda][indb][inde] = mu;
1517 if (gasok[2] && (update || !existing[2])) {
1518 m_eDifL[inda][indb][inde] = dl / sqrp;
1520 if (gasok[3] && (update || !existing[3])) {
1521 m_eAlp[inda][indb][inde] = alpha + logp;
1522 m_eAlp0[inda][indb][inde] = alpha0 + logp;
1524 if (gasok[5] && (update || !existing[5])) {
1525 m_eAtt[inda][indb][inde] = eta + logp;
1527 if (gasok[6] && (update || !existing[6])) {
1528 m_eLor[inda][indb][inde] = lor;
1530 if (gasok[7] && (update || !existing[7])) {
1531 m_eDifT[inda][indb][inde] = dt / sqrp;
1533 if (gasok[8] && (update || !existing[8])) {
1534 m_eVelB[inda][indb][inde] = vb;
1536 if (gasok[9] && (update || !existing[9])) {
1537 m_eVelX[inda][indb][inde] = vx;
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;
1544 if (gasok[11] && (update || !existing[11])) {
1545 m_iDis[inda][indb][inde] = dis + logp;
1547 if (gasok[14] && (update || !existing[14])) {
1548 for (
unsigned int l = 0; l < nexc; ++l) {
1552 if (gasok[15] && (update || !existing[15])) {
1553 for (
unsigned int l = 0; l < nion; ++l) {
1564 <<
"Replacing extrapolation and interpolation data.\n";
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]};
1587 if (
m_debug && (ionDiffL > 0. || ionDiffT > 0.)) {
1588 std::cout <<
m_className <<
"::MergeGasFile: Replacing ion diffusion.\n";
1590 if (ionDiffL > 0.)
Init(nE, nB, nA,
m_iDifL, ionDiffL);
1591 if (ionDiffT > 0.)
Init(nE, nB, nA,
m_iDifT, ionDiffT);
1601 for (
int k = 0; k < na; ++k) {
1602 for (
int j = 0; j < nb; ++j) {
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) {
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];
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.));
1658 dif[k].resize(nb + 1, std::vector<double>(ne, 0.));
1661 exc[k].resize(nb + 1, std::vector<double>(ne, 0.));
1664 ion[k].resize(nb + 1, std::vector<double>(ne, 0.));
1666 for (
int i = 0; i < ne; ++i) {
1667 for (
int j = nb; j > ib; j--) {
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];
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--) {
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];
1732 for (
int k = 0; k < na; ++k) {
1733 for (
int j = 0; j < nb; ++j) {
1740 for (
int k = 0; k < na; ++k) {
1741 for (
int i = 0; i < ne; ++i) {
1748 for (
int j = 0; j < nb; ++j) {
1749 for (
int i = 0; i < ne; ++i) {
1762 constexpr int nMagboltzGases = 60;
1763 std::vector<double> mixture(nMagboltzGases, 0.);
1768 <<
" Error retrieving gas number for " <<
m_gas[i] <<
".\n";
1776 <<
" Writing gas tables to file " << filename <<
"\n";
1779 std::ofstream outfile;
1780 outfile.open(filename.c_str(), std::ios::out);
1781 if (!outfile.is_open()) {
1783 <<
" Cannot open file " << filename <<
".\n";
1789 std::bitset<20> gasok;
1791 std::string okstr(20,
'F');
1792 for (
unsigned int i = 0; i < 20; ++i) {
1793 if (gasok[i]) okstr[i] =
'T';
1795 if (
m_debug) std::cout <<
" GASOK bits: " << okstr <<
"\n";
1797 time_t rawtime = time(0);
1798 tm timeinfo = *localtime(&rawtime);
1799 char datebuf[80] = {0};
1800 char timebuf[80] = {0};
1802 strftime(datebuf,
sizeof(datebuf) - 1,
"%d/%m/%y", &timeinfo);
1803 strftime(timebuf,
sizeof(timebuf) - 1,
"%H.%M.%S", &timeinfo);
1805 std::string member =
"< none >";
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 ";
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;
1825 outfile <<
" Identifier: " << std::setw(80) << std::left << ids.str() <<
"\n";
1826 outfile <<
" Clusters : " << std::string(80,
' ') <<
"\n";
1827 outfile <<
" Dimension : ";
1834 const unsigned int nE =
m_eFields.size();
1835 const unsigned int nB =
m_bFields.size();
1836 const unsigned int nA =
m_bAngles.size();
1839 <<
"Dataset has the following dimensions:\n "
1840 <<
"3D = " <<
m_tab2d <<
" nE = " << nE <<
", nB = " << nB
1841 <<
", nA = " << nA <<
", nExc = "
1844 outfile << FmtInt(nE, 9) <<
" " << FmtInt(nA, 9) <<
" "
1845 << FmtInt(nB, 9) <<
" " << FmtInt(
m_excLevels.size(), 9) <<
" "
1848 outfile <<
" E fields \n";
1849 std::vector<double> efields =
m_eFields;
1853 PrintArray(efields, outfile, cnt, 5);
1854 if (nE % 5 != 0) outfile <<
"\n";
1856 outfile <<
" E-B angles \n";
1859 if (nA % 5 != 0) outfile <<
"\n";
1861 outfile <<
" B fields \n";
1862 std::vector<double> bfields =
m_bFields;
1863 for (
auto& field : bfields) field *= 100.;
1865 PrintArray(bfields, outfile, cnt, 5);
1866 if (nB % 5 != 0) outfile <<
"\n";
1869 outfile <<
" Mixture: \n";
1871 PrintArray(mixture, outfile, cnt, 5);
1872 if (nMagboltzGases % 5 != 0) outfile <<
"\n";
1877 outfile <<
" Excitation " << FmtInt(cnt, 5) <<
": " << std::setw(45);
1879 if (exc.label.find(
" ") != std::string::npos) {
1880 outfile <<
"\"" + exc.label +
"\"";
1882 outfile << exc.label;
1884 outfile <<
" " << FmtFloat(exc.energy) << FmtFloat(exc.prob)
1885 << FmtFloat(exc.rms) << FmtFloat(exc.dt) <<
"\n";
1890 outfile <<
" Ionisation " << FmtInt(cnt, 5) <<
": " << std::setw(45);
1892 if (ion.label.find(
" ") != std::string::npos) {
1893 outfile <<
"\"" + ion.label <<
"\"";
1895 outfile << ion.label;
1897 outfile <<
" " << FmtFloat(ion.energy) <<
"\n";
1902 outfile <<
" The gas tables follow:\n";
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) {
1916 std::vector<double> val;
1921 val = {ve, 0., vb, 0., vx, 0.};
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;
1932 val.insert(val.end(), {dl, dt, alpha, alpha0, eta});
1934 val.insert(val.end(), {dl, 0., dt, 0., alpha, 0., alpha0, eta, 0.});
1937 double mu =
m_iMob.empty() ? 0. : 1.e3 *
m_iMob[j][k][i];
1941 double diss =
m_iDis.empty() ? -30. :
m_iDis[j][k][i] - logp;
1944 val.insert(val.end(), {mu, lor, diss});
1946 val.insert(val.end(), {mu, 0., lor, 0., diss, 0.});
1949 for (
int l = 0; l < 6; ++l) {
1956 if (!
m_tab2d) val.push_back(0.);
1960 if (rexc[j][k][i] > Small) {
1961 val.push_back(rexc[j][k][i]);
1965 if (!
m_tab2d) val.push_back(0.);
1968 if (rion[j][k][i] > Small) {
1969 val.push_back(rion[j][k][i]);
1973 if (!
m_tab2d) val.push_back(0.);
1975 PrintArray(val, outfile, cnt, 8);
1977 if (cnt % 8 != 0) outfile <<
"\n";
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;
2004 outfile <<
" H Extr: ";
2005 for (
int i = 0; i < 13; i++) outfile << FmtInt(extrapH[i], 5);
2007 outfile <<
" L Extr: ";
2008 for (
int i = 0; i < 13; i++) outfile << FmtInt(extrapL[i], 5);
2012 outfile <<
" Thresholds: " << FmtInt(
m_eThrAlp + 1, 10)
2016 interp[0] = interp[1] = interp[2] =
m_intpVel;
2017 interp[3] = interp[8] = interp[10] =
m_intpDif;
2025 outfile <<
" Interp: ";
2026 for (
int i = 0; i < 13; i++) outfile << FmtInt(interp[i], 5);
2028 outfile <<
" A =" << FmtFloat(0.) <<
", Z =" << FmtFloat(0.) <<
","
2029 <<
" EMPROB=" << FmtFloat(0.) <<
", EPAIR =" << FmtFloat(0.) <<
"\n";
2032 outfile <<
" Ion diffusion: " << FmtFloat(dli) << FmtFloat(dti) <<
"\n";
2033 outfile <<
" CMEAN =" << FmtFloat(0.) <<
", RHO =" << FmtFloat(0.) <<
","
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";
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);
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);
2070 <<
" Gas composition: " <<
m_name;
2079 std::cout <<
" Pressure: " <<
m_pressure <<
" Torr\n"
2085 std::cout <<
" Electric field range: " <<
m_eFields[0] <<
" - "
2089 std::cout <<
" Electric field: " <<
m_eFields[0] <<
" V/cm\n";
2091 std::cout <<
" Electric field range: not set\n";
2094 std::cout <<
" Magnetic field range: " <<
m_bFields[0] <<
" - "
2098 std::cout <<
" Magnetic field: " <<
m_bFields[0] <<
" T\n";
2100 std::cout <<
" Magnetic field range: not set\n";
2103 std::cout <<
" Angular range: " <<
m_bAngles[0] <<
" - "
2107 std::cout <<
" Angle between E and B: " <<
m_bAngles[0] <<
" rad\n";
2109 std::cout <<
" Angular range: not set\n";
2112 std::cout <<
" Available electron transport data:\n";
2114 std::cout <<
" Velocity along E\n";
2117 std::cout <<
" Velocity along Bt\n";
2120 std::cout <<
" Velocity along ExB\n";
2125 std::cout <<
" Interpolation order: " <<
m_intpVel <<
"\n";
2128 std::cout <<
" Longitudinal diffusion coefficient\n";
2131 std::cout <<
" Transverse diffusion coefficient\n";
2134 std::cout <<
" Diffusion tensor\n";
2138 std::cout <<
" Interpolation order: " <<
m_intpDif <<
"\n";
2141 std::cout <<
" Townsend coefficient\n";
2143 std::cout <<
" Interpolation order: " <<
m_intpAlp <<
"\n";
2146 std::cout <<
" Attachment coefficient\n";
2148 std::cout <<
" Interpolation order: " <<
m_intpAtt <<
"\n";
2151 std::cout <<
" Lorentz Angle\n";
2153 std::cout <<
" Interpolation order: " <<
m_intpLor <<
"\n";
2156 std::cout <<
" Excitation rates\n";
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;
2166 std::cout <<
" Interpolation order: " <<
m_intpExc <<
"\n";
2169 std::cout <<
" Ionisation rates\n";
2171 std::cout <<
" " << ion.label <<
"\n";
2172 std::cout <<
" Threshold = " << ion.energy <<
" eV\n";
2175 std::cout <<
" Interpolation order: " <<
m_intpIon <<
"\n";
2181 std::cout <<
" none\n";
2184 std::cout <<
" Available ion transport data:\n";
2186 std::cout <<
" Mobility\n";
2188 std::cout <<
" Interpolation order: " <<
m_intpMob <<
"\n";
2191 std::cout <<
" Longitudinal diffusion coefficient\n";
2194 std::cout <<
" Transverse diffusion coefficient\n";
2198 std::cout <<
" Interpolation order: " <<
m_intpDif <<
"\n";
2201 std::cout <<
" Dissociation coefficient\n";
2203 std::cout <<
" Interpolation order: " <<
m_intpDis <<
"\n";
2206 std::cout <<
" none\n";
2212 std::ifstream infile;
2213 infile.open(filename.c_str(), std::ios::in);
2216 std::cerr <<
m_className <<
"::LoadIonMobility:\n"
2217 <<
" Error opening file " << filename <<
".\n";
2222 double field = -1., mu = -1.;
2223 double lastField = field;
2224 std::vector<double> efields;
2225 std::vector<double> mobilities;
2229 while (!infile.eof()) {
2233 infile.getline(line, 100);
2234 char* token = strtok(line,
" ,\t");
2237 }
else if (strcmp(token,
"#") == 0 || strcmp(token,
"*") == 0 ||
2238 strcmp(token,
"//") == 0) {
2241 field = atof(token);
2242 token = strtok(NULL,
" ,\t");
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";
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";
2259 std::cout <<
" E/N = " << field <<
" Td: mu = " << mu <<
" cm2/(Vs)\n";
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";
2271 std::cerr <<
m_className <<
"::LoadIonMobility:\n";
2272 std::cerr <<
" Negative electric field (line " << i <<
").\n";
2276 if (field <= lastField) {
2277 std::cerr <<
m_className <<
"::LoadIonMobility:\n";
2278 std::cerr <<
" Table is not in ascending order (line " << i <<
").\n";
2282 efields.push_back(field);
2283 mobilities.push_back(mu);
2287 const int ne = efields.size();
2289 std::cerr <<
m_className <<
"::LoadIonMobilities:\n";
2290 std::cerr <<
" No valid data found.\n";
2297 const double scaleMobility = 1.e-9 * (AtmosphericPressure /
m_pressure) *
2299 for (
int j = ne; j--;) {
2301 efields[j] *= scaleField;
2302 mobilities[j] *= scaleMobility;
2305 std::cout <<
m_className <<
"::LoadIonMobility:\n";
2306 std::cout <<
" Read " << ne <<
" values from file " << filename <<
"\n";
2322 const double lambda) {
2324 if (r < 0. || r > 1.) {
2325 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2326 <<
" Transfer probability must be in the range [0, 1].\n";
2333 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2334 <<
" Global Penning transfer parameters set to:\n"
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";
2345 double minIonPot = -1.;
2347 if (minIonPot < 0.) {
2348 minIonPot = ion.energy;
2350 minIonPot = std::min(minIonPot, ion.energy);
2355 unsigned int nLevelsFound = 0;
2357 if (exc.energy < minIonPot)
continue;
2362 if (nLevelsFound > 0) {
2363 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2364 <<
" Updated transfer probabilities for " << nLevelsFound
2365 <<
" excitation rates.\n";
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";
2376 std::string gasname) {
2378 if (r < 0. || r > 1.) {
2379 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2380 <<
" Transfer probability must be in the range [0, 1].\n";
2386 if (gasname.empty()) {
2387 std::cerr <<
m_className <<
"::EnablePenningTransfer: Unknown gas name.\n";
2394 if (
m_gas[i] == gasname) {
2403 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2404 <<
" Requested gas (" << gasname
2405 <<
") is not part of the present gas mixture.\n";
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";
2416 double minIonPot = -1.;
2418 if (minIonPot < 0.) {
2419 minIonPot = ion.energy;
2421 minIonPot = std::min(minIonPot, ion.energy);
2425 unsigned int nLevelsFound = 0;
2427 if (exc.energy < minIonPot)
continue;
2430 const auto pos = exc.label.find(
'-');
2431 if (pos == std::string::npos)
continue;
2432 if (
GetGasName(exc.label.substr(0, pos)) != gasname)
continue;
2437 if (nLevelsFound > 0) {
2438 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2439 <<
" Updated transfer probabilities for " << nLevelsFound
2440 <<
" excitation rates.\n";
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";
2469 if (gasname.empty()) {
2470 std::cerr <<
m_className <<
"::DisablePenningTransfer: Unknown gas name.\n";
2477 if (
m_gas[i] == gasname) {
2486 std::cerr <<
m_className <<
"::DisablePenningTransfer:\n"
2487 <<
" Requested gas (" << gasname
2488 <<
") is not part of the present gas mixture.\n";
2495 const auto pos = exc.label.find(
'-');
2496 if (pos == std::string::npos)
continue;
2497 if (
GetGasName(exc.label.substr(0, pos)) != gasname)
continue;
2513 std::cerr <<
m_className <<
"::AdjustTownsendCoefficient:\n "
2514 <<
"Present gas table does not include Townsend coefficients.\n";
2519 std::cerr <<
m_className <<
"::AdjustTownsendCoefficient:\n "
2520 <<
"Present gas table does not include excitation rates.\n";
2524 std::cerr <<
m_className <<
"::AdjustTownsendCoefficient:\n "
2525 <<
"Present gas table does not include ionisation rates.\n";
2528 const unsigned int nE =
m_eFields.size();
2529 const unsigned int nB =
m_bFields.size();
2530 const unsigned int nA =
m_bAngles.size();
2532 std::cout <<
m_className <<
"::AdjustTownsendCoefficient:\n"
2533 <<
" Entry Exc. Ion.\n";
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) {
2541 rion += ion[j][k][i];
2546 for (
unsigned int ie = 0; ie < nexc; ++ie) {
2550 std::cout << FmtInt(i, 4) << FmtInt(j, 4) << FmtInt(k, 4)
2551 << FmtFloat(rexc, 12, 5) << FmtFloat(rion, 12, 5) <<
"\n";
2554 double alpha0 =
m_eAlp0[j][k][i];
2555 if (alpha0 < -20.) {
2560 double alpha1 = alpha0;
2561 if (rion > 0.) alpha1 *= (rexc + rion) / rion;
2573 if (gasname ==
"CF4") {
2574 a = 12.0107 + 4 * 18.9984032;
2577 }
else if (gasname ==
"Ar") {
2580 }
else if (gasname ==
"He") {
2583 }
else if (gasname ==
"He-3") {
2586 }
else if (gasname ==
"Ne") {
2589 }
else if (gasname ==
"Kr") {
2592 }
else if (gasname ==
"Xe") {
2595 }
else if (gasname ==
"CH4") {
2596 a = 12.0107 + 4 * 1.00794;
2598 }
else if (gasname ==
"C2H6") {
2599 a = 2 * 12.0107 + 6 * 1.00794;
2601 }
else if (gasname ==
"C3H8") {
2602 a = 3 * 12.0107 + 8 * 1.00794;
2604 }
else if (gasname ==
"iC4H10") {
2605 a = 4 * 12.0107 + 10 * 1.00794;
2607 }
else if (gasname ==
"CO2") {
2608 a = 12.0107 + 2 * 15.9994;
2610 }
else if (gasname ==
"neoC5H12") {
2611 a = 5 * 12.0107 + 12 * 1.00794;
2613 }
else if (gasname ==
"H2O") {
2614 a = 2 * 1.00794 + 15.9994;
2616 }
else if (gasname ==
"O2") {
2619 }
else if (gasname ==
"N2") {
2622 }
else if (gasname ==
"NO") {
2623 a = 14.0067 + 15.9994;
2625 }
else if (gasname ==
"N2O") {
2626 a = 2 * 14.0067 + 15.9994;
2628 }
else if (gasname ==
"C2H4") {
2629 a = 2 * 12.0107 + 4 * 1.00794;
2631 }
else if (gasname ==
"C2H2") {
2632 a = 2 * 12.0107 + 2 * 1.00794;
2634 }
else if (gasname ==
"H2" || gasname ==
"paraH2") {
2637 }
else if (gasname ==
"D2" || gasname ==
"orthoD2") {
2638 a = 2 * 2.01410177785;
2640 }
else if (gasname ==
"CO") {
2641 a = 12.0107 + 15.9994;
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") {
2653 }
else if (gasname ==
"C2F6") {
2654 a = 2 * 12.0107 + 6 * 18.9984032;
2656 }
else if (gasname ==
"SF6") {
2657 a = 32.065 + 6 * 18.9984032;
2659 }
else if (gasname ==
"NH3") {
2660 a = 14.0067 + 3 * 1.00794;
2662 }
else if (gasname ==
"C3H6") {
2663 a = 3 * 12.0107 + 6 * 1.00794;
2665 }
else if (gasname ==
"cC3H6") {
2666 a = 3 * 12.0107 + 6 * 1.00794;
2668 }
else if (gasname ==
"CH3OH") {
2669 a = 12.0107 + 4 * 1.00794 + 15.9994;
2671 }
else if (gasname ==
"C2H5OH") {
2672 a = 2 * 12.0107 + 6 * 1.00794 + 15.9994;
2674 }
else if (gasname ==
"C3H7OH" || gasname ==
"nC3H7OH") {
2675 a = 3 * 12.0107 + 8 * 1.00794 + 15.9994;
2677 }
else if (gasname ==
"Cs") {
2680 }
else if (gasname ==
"F2") {
2683 }
else if (gasname ==
"CS2") {
2684 a = 12.0107 + 2 * 32.065;
2686 }
else if (gasname ==
"COS") {
2687 a = 12.0107 + 15.9994 + 32.065;
2689 }
else if (gasname ==
"CD4") {
2690 a = 12.0107 + 4 * 2.01410177785;
2692 }
else if (gasname ==
"BF3") {
2693 a = 10.811 + 3 * 18.9984032;
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;
2701 }
else if (gasname ==
"CF3Br") {
2702 a = 12.0107 + 3 * 18.9984032 + 79.904;
2704 }
else if (gasname ==
"C3F8") {
2705 a = 3 * 12.0107 + 8 * 18.9984032;
2707 }
else if (gasname ==
"O3") {
2710 }
else if (gasname ==
"Hg") {
2713 }
else if (gasname ==
"H2S") {
2714 a = 2 * 1.00794 + 32.065;
2716 }
else if (gasname ==
"nC4H10") {
2717 a = 4 * 12.0107 + 10 * 1.00794;
2719 }
else if (gasname ==
"nC5H12") {
2720 a = 5 * 12.0107 + 12 * 1.00794;
2722 }
else if (gasname ==
"N2") {
2725 }
else if (gasname ==
"GeH4") {
2726 a = 72.64 + 4 * 1.00794;
2728 }
else if (gasname ==
"SiH4") {
2729 a = 28.0855 + 4 * 1.00794;
2742 switch (gasnumber) {
2822 return "Maxwell-Model";
2873 return version <= 11 ?
"He-3" :
"TMA";
2876 return version <= 11 ?
"He" :
"paraH2";
2879 return version <= 11 ?
"Ne" :
"nC3H7OH";
2885 return version <= 11 ?
"Kr" :
"orthoD2";
2932 for (
unsigned int i = 0; i < input.length(); ++i) {
2933 input[i] = toupper(input[i]);
2936 if (input.empty())
return "";
2938 if (input ==
"CF4" || input ==
"FREON" || input ==
"FREON-14" ||
2939 input ==
"TETRAFLUOROMETHANE") {
2941 }
else if (input ==
"AR" || input ==
"ARGON") {
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") {
2948 }
else if (input ==
"HE-3" || input ==
"HE3" || input ==
"HELIUM-3" ||
2949 input ==
"HELIUM 3" || input ==
"HELIUM3") {
2951 }
else if (input ==
"NE" || input ==
"NEON") {
2953 }
else if (input ==
"KR" || input ==
"KRYPTON") {
2955 }
else if (input ==
"XE" || input ==
"XENON") {
2957 }
else if (input ==
"CH4" || input ==
"METHANE") {
2959 }
else if (input ==
"C2H6" || input ==
"ETHANE") {
2961 }
else if (input ==
"C3H8" || input ==
"PROPANE") {
2963 }
else if (input ==
"C4H10" || input ==
"ISOBUTANE" || input ==
"ISO" ||
2964 input ==
"IC4H10" || input ==
"ISO-C4H10" || input ==
"ISOC4H10") {
2966 }
else if (input ==
"CO2" || input ==
"CARBON-DIOXIDE" ||
2967 input ==
"CARBON DIOXIDE" || input ==
"CARBONDIOXIDE") {
2969 }
else if (input ==
"NEOPENTANE" || input ==
"NEO-PENTANE" ||
2970 input ==
"NEO-C5H12" || input ==
"NEOC5H12" ||
2971 input ==
"DIMETHYLPROPANE" || input ==
"C5H12") {
2973 }
else if (input ==
"H2O" || input ==
"WATER" || input ==
"WATER-VAPOUR" ||
2974 input ==
"WATER VAPOUR") {
2976 }
else if (input ==
"O2" || input ==
"OXYGEN") {
2978 }
else if (input ==
"NI" || input ==
"NITRO" || input ==
"N2" ||
2979 input ==
"NITROGEN") {
2981 }
else if (input ==
"NO" || input ==
"NITRIC-OXIDE" || input ==
"NITRIC OXIDE" ||
2982 input ==
"NITROGEN-MONOXIDE" || input ==
"NITROGEN MONOXIDE") {
2984 }
else if (input ==
"N2O" || input ==
"NITROUS-OXIDE" || input ==
"NITROUS OXIDE" ||
2985 input ==
"DINITROGEN-MONOXIDE" || input ==
"LAUGHING-GAS") {
2987 }
else if (input ==
"C2H4" || input ==
"ETHENE" || input ==
"ETHYLENE") {
2989 }
else if (input ==
"C2H2" || input ==
"ACETYL" || input ==
"ACETYLENE" ||
2990 input ==
"ETHYNE") {
2992 }
else if (input ==
"H2" || input ==
"HYDROGEN") {
2994 }
else if (input ==
"PARA H2" || input ==
"PARA-H2" ||
2995 input ==
"PARAH2" || input ==
"PARA HYDROGEN" ||
2996 input ==
"PARA-HYDROGEN" || input ==
"PARAHYDROGEN") {
2998 }
else if (input ==
"D2" || input ==
"DEUTERIUM") {
3000 }
else if (input ==
"ORTHO D2" || input ==
"ORTHO-D2" ||
3001 input ==
"ORTHOD2" || input ==
"ORTHO DEUTERIUM" ||
3002 input ==
"ORTHO-DEUTERIUM" || input ==
"ORTHODEUTERIUM") {
3004 }
else if (input ==
"CO" || input ==
"CARBON-MONOXIDE" ||
3005 input ==
"CARBON MONOXIDE") {
3007 }
else if (input ==
"METHYLAL" || input ==
"METHYLAL-HOT" || input ==
"DMM" ||
3008 input ==
"DIMETHOXYMETHANE" || input ==
"FORMAL" || input ==
"C3H8O2") {
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") {
3018 }
else if (input ==
"REID-STEP") {
3020 }
else if (input ==
"MAXWELL-MODEL") {
3021 return "Maxwell-Model";
3022 }
else if (input ==
"REID-RAMP") {
3024 }
else if (input ==
"C2F6" || input ==
"FREON-116" || input ==
"ZYRON-116" ||
3025 input ==
"ZYRON-116-N5" || input ==
"HEXAFLUOROETHANE") {
3027 }
else if (input ==
"SF6" || input ==
"SULPHUR-HEXAFLUORIDE" ||
3028 input ==
"SULFUR-HEXAFLUORIDE" || input ==
"SULPHUR HEXAFLUORIDE" ||
3029 input ==
"SULFUR HEXAFLUORIDE") {
3031 }
else if (input ==
"NH3" || input ==
"AMMONIA") {
3033 }
else if (input ==
"C3H6" || input ==
"PROPENE" || input ==
"PROPYLENE") {
3035 }
else if (input ==
"C-PROPANE" || input ==
"CYCLO-PROPANE" ||
3036 input ==
"CYCLO PROPANE" || input ==
"CYCLOPROPANE" ||
3037 input ==
"C-C3H6" || input ==
"CC3H6" || input ==
"CYCLO-C3H6") {
3039 }
else if (input ==
"METHANOL" || input ==
"METHYL-ALCOHOL" ||
3040 input ==
"METHYL ALCOHOL" || input ==
"WOOD ALCOHOL" ||
3041 input ==
"WOOD-ALCOHOL" || input ==
"CH3OH") {
3043 }
else if (input ==
"ETHANOL" || input ==
"ETHYL-ALCOHOL" ||
3044 input ==
"ETHYL ALCOHOL" || input ==
"GRAIN ALCOHOL" ||
3045 input ==
"GRAIN-ALCOHOL" || input ==
"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") {
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") {
3057 }
else if (input ==
"CS" || input ==
"CESIUM" || input ==
"CAESIUM") {
3059 }
else if (input ==
"F2" || input ==
"FLUOR" || input ==
"FLUORINE") {
3061 }
else if (input ==
"CS2" || input ==
"CARBON-DISULPHIDE" ||
3062 input ==
"CARBON-DISULFIDE" || input ==
"CARBON DISULPHIDE" ||
3063 input ==
"CARBON DISULFIDE") {
3065 }
else if (input ==
"COS" || input ==
"CARBONYL-SULPHIDE" ||
3066 input ==
"CARBONYL-SULFIDE" || input ==
"CARBONYL SULFIDE") {
3068 }
else if (input ==
"DEUT-METHANE" || input ==
"DEUTERIUM-METHANE" ||
3069 input ==
"DEUTERATED-METHANE" || input ==
"DEUTERATED METHANE" ||
3070 input ==
"DEUTERIUM METHANE" || input ==
"CD4") {
3072 }
else if (input ==
"BF3" || input ==
"BORON-TRIFLUORIDE" ||
3073 input ==
"BORON TRIFLUORIDE") {
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") {
3082 }
else if (input ==
"TMA" || input ==
"TRIMETHYLAMINE" || input ==
"N(CH3)3" ||
3083 input ==
"N-(CH3)3") {
3085 }
else if (input ==
"CHF3" || input ==
"FREON-23" || input ==
"TRIFLUOROMETHANE" ||
3086 input ==
"FLUOROFORM") {
3088 }
else if (input ==
"CF3BR" || input ==
"TRIFLUOROBROMOMETHANE" ||
3089 input ==
"BROMOTRIFLUOROMETHANE" || input ==
"HALON-1301" ||
3090 input ==
"HALON 1301" || input ==
"FREON-13B1" || input ==
"FREON 13BI") {
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") {
3098 }
else if (input ==
"OZONE" || input ==
"O3") {
3100 }
else if (input ==
"MERCURY" || input ==
"HG" || input ==
"HG2") {
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") {
3113 }
else if (input ==
"N-BUTANE" || input ==
"N-C4H10" || input ==
"NBUTANE" ||
3114 input ==
"NC4H10") {
3116 }
else if (input ==
"N-PENTANE" || input ==
"N-C5H12" || input ==
"NPENTANE" ||
3117 input ==
"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)") {
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") {
3129 }
else if (input ==
"SILANE" || input ==
"SIL" || input ==
"SILICON-HYDRIDE" ||
3130 input ==
"SILICON HYDRIDE" || input ==
"SILICON-TETRAHYDRIDE" ||
3131 input ==
"SILICANE" || input ==
"MONOSILANE" || input ==
"SIH4") {
3136 <<
" Gas " << input <<
" is not recognized.\n";
3142 if (input.empty())
return 0;
3144 if (input ==
"CF4") {
3146 }
else if (input ==
"Ar") {
3148 }
else if (input ==
"He" || input ==
"He-4") {
3150 }
else if (input ==
"He-3") {
3152 }
else if (input ==
"Ne") {
3154 }
else if (input ==
"Kr") {
3156 }
else if (input ==
"Xe") {
3158 }
else if (input ==
"CH4") {
3161 }
else if (input ==
"C2H6") {
3164 }
else if (input ==
"C3H8") {
3167 }
else if (input ==
"iC4H10") {
3170 }
else if (input ==
"CO2") {
3172 }
else if (input ==
"neoC5H12") {
3175 }
else if (input ==
"H2O") {
3177 }
else if (input ==
"O2") {
3179 }
else if (input ==
"N2") {
3181 }
else if (input ==
"NO") {
3184 }
else if (input ==
"N2O") {
3187 }
else if (input ==
"C2H4") {
3190 }
else if (input ==
"C2H2") {
3193 }
else if (input ==
"H2") {
3195 }
else if (input ==
"D2") {
3198 }
else if (input ==
"CO") {
3200 }
else if (input ==
"Methylal") {
3203 }
else if (input ==
"DME") {
3205 }
else if (input ==
"Reid-Step") {
3207 }
else if (input ==
"Maxwell-Model") {
3209 }
else if (input ==
"Reid-Ramp") {
3211 }
else if (input ==
"C2F6") {
3213 }
else if (input ==
"SF6") {
3215 }
else if (input ==
"NH3") {
3217 }
else if (input ==
"C3H6") {
3220 }
else if (input ==
"cC3H6") {
3223 }
else if (input ==
"CH3OH") {
3226 }
else if (input ==
"C2H5OH") {
3229 }
else if (input ==
"C3H7OH") {
3232 }
else if (input ==
"Cs") {
3234 }
else if (input ==
"F2") {
3237 }
else if (input ==
"CS2") {
3239 }
else if (input ==
"COS") {
3241 }
else if (input ==
"CD4") {
3244 }
else if (input ==
"BF3") {
3246 }
else if (input ==
"C2HF5" || input ==
"C2H2F4") {
3248 }
else if (input ==
"TMA") {
3250 }
else if (input ==
"paraH2") {
3252 }
else if (input ==
"nC3H7OH") {
3254 }
else if (input ==
"orthoD2") {
3256 }
else if (input ==
"CHF3") {
3258 }
else if (input ==
"CF3Br") {
3260 }
else if (input ==
"C3F8") {
3262 }
else if (input ==
"O3") {
3265 }
else if (input ==
"Hg") {
3267 }
else if (input ==
"H2S") {
3269 }
else if (input ==
"nC4H10") {
3272 }
else if (input ==
"nC5H12") {
3275 }
else if (input ==
"N2 (Phelps)") {
3277 }
else if (input ==
"GeH4") {
3280 }
else if (input ==
"SiH4") {
3285 std::cerr <<
m_className <<
"::GetGasNumberGasFile:\n"
3286 <<
" Gas " << input <<
" not found.\n";
3291 const unsigned int i) {
3294 <<
"::GetPhotoAbsorptionCrossSection: Index out of range.\n";
double GetMassDensity() const override
Get the mass density [g/cm3].
double GetNumberDensity() const override
Get the number density [cm-3].
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)
bool AdjustTownsendCoefficient()
std::pair< unsigned int, unsigned int > m_extrIon
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 SetAtomicNumber(const double z) override
Set the effective atomic number.
bool GetGasInfo(const std::string &gasname, double &a, double &z) const
static constexpr unsigned int m_nMaxGases
std::vector< std::vector< std::vector< std::vector< double > > > > m_excRates
void InsertB(const int ib, const int ne, const int nb, const int na)
double m_lambdaPenningGlobal
std::vector< IonLevel > m_ionLevels
std::array< double, m_nMaxGases > m_rPenningGas
bool LoadIonMobility(const std::string &filename)
Read a table of ion mobilities as function of electric field from file.
double GetAtomicNumber() const override
Get the effective atomic number.
std::array< double, m_nMaxGases > m_atNum
void GetGasBits(std::bitset< 20 > &gasok) const
std::vector< std::vector< std::vector< std::vector< double > > > > m_ionRates
void ZeroRowA(const int ia, const int ne, const int nb)
void ResetTables() override
Reset all tables of transport parameters.
std::vector< ExcLevel > m_excLevels
void ZeroRowB(const int ib, const int ne, const int na)
int GetGasNumberGasFile(const std::string &input) const
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)
double m_temperatureTable
virtual void PrintGas()
Print information about the present gas mixture and available data.
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)
std::array< double, m_nMaxGases > m_atWeight
void GetComponent(const unsigned int i, std::string &label, double &f) override
Get the name and fraction of a given component.
bool WriteGasFile(const std::string &filename)
Save the present table of gas properties (transport parameters) to a file.
bool GetMixture(const std::vector< double > &mixture, const int version, std::vector< std::string > &gasnames, std::vector< double > &percentages) const
std::array< double, m_nMaxGases > m_lambdaPenningGas
std::pair< unsigned int, unsigned int > m_extrExc
bool GetPhotoAbsorptionCrossSection(const double e, double &sigma, const unsigned int i) override
bool MergeGasFile(const std::string &filename, const bool replaceOld)
Read table of gas properties from and merge with the existing dataset.
virtual void DisablePenningTransfer()
Switch the simulation of Penning transfers off globally.
std::string GetGasName(const int gasnumber, const int version) const
double GetAtomicWeight() const override
Get the effective atomic weight.
void SetNumberDensity(const double n) override
Set the number density [cm-3].
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 ZeroRowE(const int ie, const int nb, const int na)
void SetMassDensity(const double rho) override
Set the mass density [g/cm3].
virtual bool EnablePenningTransfer(const double r, const double lambda)
std::vector< std::vector< std::vector< double > > > m_eAlp0
void InsertA(const int ia, const int ne, const int nb, const int na)
bool LoadGasFile(const std::string &filename)
Read table of gas properties (transport parameters) from file.
void InsertE(const int ie, const int ne, const int nb, const int na)
std::array< std::string, m_nMaxGases > m_gas
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 SetAtomicWeight(const double a) override
Set the effective atomic weight.
std::array< double, m_nMaxGases > m_fraction
Abstract base class for media.
std::vector< double > m_bFields
unsigned int SetThreshold(const std::vector< std::vector< std::vector< double > > > &tab) const
std::vector< std::vector< std::vector< double > > > m_eAlp
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.
std::pair< unsigned int, unsigned int > m_extrAtt
std::vector< std::vector< std::vector< double > > > m_iDifT
std::pair< unsigned int, unsigned int > m_extrVel
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_eDifL
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)
std::vector< double > m_eFields
std::vector< std::vector< std::vector< double > > > m_eAtt
std::vector< double > m_bAngles
std::vector< std::vector< std::vector< double > > > m_iDifL
std::vector< std::vector< std::vector< double > > > m_eLor
std::vector< std::vector< std::vector< double > > > m_eDifT
std::pair< unsigned int, unsigned int > m_extrDis
std::pair< unsigned int, unsigned int > m_extrAlp
std::vector< std::vector< std::vector< double > > > m_eVelB
std::pair< unsigned int, unsigned int > m_extrLor
unsigned int m_nComponents
std::pair< unsigned int, unsigned int > m_extrDif
virtual void ResetTables()
Reset all tables of transport parameters.
std::pair< unsigned int, unsigned int > m_extrMob
std::vector< std::vector< std::vector< std::vector< double > > > > m_eDifM
std::vector< std::vector< std::vector< double > > > m_iMob
std::vector< std::vector< std::vector< double > > > m_iDis
bool SetIonMobility(const std::vector< double > &fields, const std::vector< double > &mobilities)
Photoabsorption cross-sections for some gases.
bool GetPhotoabsorptionCrossSection(const std::string &material, const double e, double &cs, double &eta)
Photo-absorption cross-section and ionisation yield at a given energy.
bool IsAvailable(const std::string &material) const
Check whether optical data have been implemented for a given gas.
DoubleAc fabs(const DoubleAc &f)