22std::string FmtFloat(
const double x,
const unsigned int width = 15,
23 const unsigned int precision = 8) {
25 std::snprintf(buffer, width + 1,
"%*.*E", width, precision, x);
26 return std::string(buffer);
29std::string FmtInt(
const int n,
const unsigned int width) {
31 if (std::snprintf(buffer, width + 1,
"%*d", width, n) < 0.) {
32 std::cout <<
" Warning: error formatting integer number " << n <<
"\n";
34 return std::string(buffer);
37void PrintArray(
const std::vector<double>& values, std::ofstream& outfile,
38 int& col,
const int ncols) {
39 for (
const auto value : values) {
40 outfile << FmtFloat(value);
42 if (col % ncols == 0) outfile <<
"\n";
46void PrintExtrapolation(
const std::pair<unsigned int, unsigned int>& extr) {
47 std::cout <<
" Low field extrapolation: ";
49 std::cout <<
" constant\n";
50 else if (extr.first == 1)
51 std::cout <<
" linear\n";
52 else if (extr.first == 2)
53 std::cout <<
" exponential\n";
55 std::cout <<
" unknown\n";
56 std::cout <<
" High field extrapolation: ";
58 std::cout <<
" constant\n";
59 else if (extr.second == 1)
60 std::cout <<
" linear\n";
61 else if (extr.second == 2)
62 std::cout <<
" exponential\n";
64 std::cout <<
" unknown\n";
67void PrintAbsentInNew(
const std::string& par) {
68 std::cout <<
" Warning: The " << par <<
" is absent in the dataset "
69 <<
"to be added; data reset.\n";
72void PrintAbsentInExisting(
const std::string& par) {
73 std::cout <<
" Warning: The " << par <<
" is absent in the existing data; "
74 <<
"new data not used.\n";
77bool Similar(
const double v1,
const double v2,
const double eps) {
78 const double dif = v1 - v2;
79 const double sum =
fabs(v1) +
fabs(v2);
80 return fabs(dif) < std::max(eps * sum, Garfield::Small);
83int Equal(
const std::vector<double>& fields1,
84 const std::vector<double>& fields2,
const double eps) {
85 if (fields1.size() != fields2.size())
return 0;
86 const size_t n = fields1.size();
87 for (
size_t i = 0; i < n; ++i) {
88 if (!Similar(fields1[i], fields2[i], eps))
return 0;
93int FindIndex(
const double field,
const std::vector<double>& fields,
96 const int n = fields.size();
97 for (
int i = 0; i < n; ++i) {
98 if (Similar(field, fields[i], eps))
return i;
103void ResizeA(std::vector<std::vector<std::vector<double> > >& tab,
104 const int ne,
const int nb,
const int na) {
105 if (tab.empty())
return;
107 std::vector<std::vector<double> >(nb,
108 std::vector<double>(ne, 0.)));
139 const std::string& gas2,
const double f2,
140 const std::string& gas3,
const double f3,
141 const std::string& gas4,
const double f4,
142 const std::string& gas5,
const double f5,
143 const std::string& gas6,
const double f6) {
144 std::array<std::string, 6> gases = {gas1, gas2, gas3, gas4, gas5, gas6};
145 std::array<double, 6> fractions = {f1, f2, f3, f4, f5, f6};
148 const std::array<std::string, m_nMaxGases> gasOld =
m_gas;
161 for (
unsigned int i = 0; i < 6; ++i) {
162 if (fractions[i] < Small)
continue;
164 const std::string gasname =
GetGasName(gases[i]);
165 if (!gasname.empty()) {
171 <<
" Unknown identifier '" << gases[i] <<
"'.\n";
178 <<
" Error setting the composition. No valid components.\n";
199 double w = 0., f = 0.;
218 std::array<double, m_nMaxGases> rPenningGasOld;
219 std::array<double, m_nMaxGases> lambdaPenningGasOld;
220 rPenningGasOld.fill(0.);
221 lambdaPenningGasOld.fill(0.);
225 for (
unsigned int j = 0; j < nComponentsOld; ++j) {
226 if (
m_gas[i] != gasOld[j])
continue;
227 if (rPenningGasOld[j] < Small)
continue;
231 <<
" Using Penning transfer parameters for " <<
m_gas[i]
232 <<
" from previous mixture.\n"
241 std::string& gas1,
double& f1, std::string& gas2,
double& f2,
242 std::string& gas3,
double& f3, std::string& gas4,
double& f4,
243 std::string& gas5,
double& f5, std::string& gas6,
double& f6)
const {
261 std::cerr <<
m_className <<
"::GetComponent: Index out of range.\n";
273 <<
" Effective Z cannot be changed directly.\n"
274 <<
" Use SetComposition to define the gas mixture.\n";
279 <<
" Effective A cannot be changed directly.\n"
280 <<
" Use SetComposition to define the gas mixture.\n";
284 std::cerr <<
m_className <<
"::SetNumberDensity:\n"
285 <<
" Density cannot be changed directly.\n"
286 <<
" Use SetTemperature and SetPressure.\n";
291 <<
" Density cannot be changed directly.\n"
292 <<
" Use SetTemperature, SetPressure and SetComposition.\n";
306 return LoschmidtNumber * (
m_pressure / AtmosphericPressure) *
330 std::ifstream gasfile(filename);
334 <<
" Cannot open file " << filename <<
".\n";
339 <<
" Reading file " << filename <<
".\n";
345 if (
m_debug) std::cout <<
" Reading header.\n";
348 std::bitset<20> gasok;
350 constexpr int nMagboltzGases = 60;
351 std::vector<double> mixture(nMagboltzGases, 0.);
357 if (!quiet) std::cout <<
" Version " << version <<
".\n";
360 std::vector<std::string> gasnames;
361 std::vector<double> percentages;
362 if (!
GetMixture(mixture, version, gasnames, percentages)) {
364 <<
"Cannot determine the gas composition.\n";
376 m_gas[i] = gasnames[i];
378 double w = 0., f = 0.;
384 std::cout <<
" Gas composition set to " <<
m_name;
399 std::cout <<
" " << nE <<
" electric field(s), " << nB
400 <<
" magnetic field(s), " << nA <<
" angle(s).\n";
435 if (gasok[11])
Init(nE, nB, nA,
m_iDis, -30.);
443 const std::string fmt =
m_tab2d ?
"3D" :
"1D";
444 std::cout <<
" Reading " << fmt <<
" table.\n";
448 double ve = 0., vb = 0., vx = 0.;
452 double dl = 0., dt = 0.;
454 double alpha = 0., alpha0 = 0., eta = 0.;
456 double mu = 0., dis = 0.;
458 std::array<double, 6> diff;
461 std::vector<double> rexc(nexc, 0.);
463 std::vector<double> rion(nion, 0.);
464 for (
int i = 0; i < nE; i++) {
465 for (
int j = 0; j < nA; j++) {
466 for (
int k = 0; k < nB; k++) {
468 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
469 lor, dis, diff, rexc, rion);
471 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
472 lor, dis, diff, rexc, rion);
488 for (
int l = 0; l < 6; l++) {
493 for (
unsigned int l = 0; l < nexc; ++l) {
498 for (
unsigned int l = 0; l < nion; ++l) {
507 std::array<unsigned int, 13> extrapH = {{0}};
508 std::array<unsigned int, 13> extrapL = {{1}};
510 std::array<unsigned int, 13> interp = {{2}};
512 double ionDiffL = 0.;
513 double ionDiffT = 0.;
518 gasfile.ignore(std::numeric_limits<std::streamsize>::max(),
'\n');
519 if (
m_debug) std::cout <<
" Reading footer.\n";
539 for (
int i = nE; i--;) {
540 for (
int j = nA; j--;) {
541 for (
int k = nB; k--;) {
589 if (ionDiffL > 0.)
Init(nE, nB, nA,
m_iDifL, ionDiffL);
590 if (ionDiffT > 0.)
Init(nE, nB, nA,
m_iDifT, ionDiffT);
592 if (
m_debug) std::cout <<
" Done.\n";
598 std::bitset<20>& gasok,
bool& is3d, std::vector<double>& mixture,
599 std::vector<double>& efields, std::vector<double>& bfields,
600 std::vector<double>& angles, std::vector<ExcLevel>& excLevels,
601 std::vector<IonLevel>& ionLevels) {
606 while (gasfile.getline(line, 256)) {
607 const bool quotes = (strstr(line,
"\"") != NULL);
608 if (strncmp(line,
" The gas tables follow:", 8) == 0 ||
609 strncmp(line,
"The gas tables follow:", 7) == 0) {
613 char* token = strtok(line,
" :,%");
615 if (strcmp(token,
"Version") == 0) {
616 token = strtok(NULL,
" :,%");
619 <<
" Cannot read version number.\n";
622 version = atoi(token);
624 if (version != 10 && version != 11 && version != 12) {
626 <<
" The file has version number " << version <<
".\n"
627 <<
" Files written in this format cannot be read.\n";
630 }
else if (strcmp(token,
"GASOK") == 0) {
633 token = strtok(NULL,
" :,%\t");
634 token = strtok(NULL,
" :,%\t");
635 std::string okstr(token);
636 if (
m_debug) std::cout <<
" GASOK bits: " << okstr <<
"\n";
637 if (okstr.size() < 20) {
639 <<
" Unexpected size of GASOK string ("
640 << okstr.size() <<
").\n";
643 for (
unsigned int i = 0; i < 20; ++i) {
644 if (okstr[i] ==
'T') gasok.set(i);
646 }
else if (strcmp(token,
"Identifier") == 0) {
648 std::string identifier =
"";
649 token = strtok(NULL,
"\n");
650 if (token != NULL) identifier += token;
651 if (
m_debug) std::cout <<
" Identifier: " << identifier <<
"\n";
652 }
else if (strcmp(token,
"Dimension") == 0) {
653 token = strtok(NULL,
" :,%\t");
654 if (strcmp(token,
"F") == 0) {
659 token = strtok(NULL,
" :,%\t");
660 const int nE = atoi(token);
664 <<
" Number of E fields out of range.\n";
667 token = strtok(NULL,
" :,%\t");
668 const int nA = atoi(token);
670 if (is3d && nA <= 0) {
672 <<
" Number of E-B angles out of range.\n";
675 token = strtok(NULL,
" :,%\t");
676 const int nB = atoi(token);
678 if (is3d && nB <= 0) {
680 <<
" Number of B fields out of range.\n";
688 token = strtok(NULL,
" :,%\t");
689 const int nexc = atoi(token);
691 token = strtok(NULL,
" :,%\t");
692 const int nion = atoi(token);
694 std::cout <<
" " << nexc <<
" excitations, " << nion
695 <<
" ionisations.\n";
697 }
else if (strcmp(token,
"E") == 0) {
698 token = strtok(NULL,
" :,%");
699 if (strncmp(token,
"fields", 6) == 0) {
700 const int nE = efields.size();
701 for (
int i = 0; i < nE; ++i) gasfile >> efields[i];
703 }
else if (strcmp(token,
"E-B") == 0) {
704 token = strtok(NULL,
" :,%");
705 if (strncmp(token,
"angles", 6) == 0) {
706 const int nA = angles.size();
707 for (
int i = 0; i < nA; ++i) gasfile >> angles[i];
709 }
else if (strcmp(token,
"B") == 0) {
710 token = strtok(NULL,
" :,%");
711 if (strncmp(token,
"fields", 6) == 0) {
713 const int nB = bfields.size();
714 for (
int i = 0; i < nB; i++) {
716 bfields[i] = bstore / 100.;
719 }
else if (strcmp(token,
"Mixture") == 0) {
720 const unsigned int nMagboltzGases = mixture.size();
721 for (
unsigned int i = 0; i < nMagboltzGases; ++i) {
722 gasfile >> mixture[i];
724 }
else if (strcmp(token,
"Excitation") == 0) {
726 token = strtok(NULL,
" :,%");
730 token = strtok(NULL,
"\"");
731 token = strtok(NULL,
"\"");
733 token = strtok(NULL,
" :,%");
737 token = strtok(NULL,
" :,%");
740 token = strtok(NULL,
" :,%");
741 exc.
prob = atof(token);
746 token = strtok(NULL,
" :,%");
748 exc.
rms = atof(token);
750 token = strtok(NULL,
" :,%");
751 if (token) exc.
dt = atof(token);
754 excLevels.push_back(std::move(exc));
755 }
else if (strcmp(token,
"Ionisation") == 0) {
757 token = strtok(NULL,
" :,%");
761 token = strtok(NULL,
"\"");
762 token = strtok(NULL,
"\"");
764 token = strtok(NULL,
" :,%");
768 token = strtok(NULL,
" :,%");
770 ionLevels.push_back(std::move(ion));
772 token = strtok(NULL,
" :,%");
779 double& ve,
double& vb,
double& vx,
double& dl,
double& dt,
780 double& alpha,
double& alpha0,
double& eta,
double& mu,
double& lor,
781 double& dis, std::array<double, 6>& dif,
782 std::vector<double>& rexc, std::vector<double>& rion) {
785 gasfile >> ve >> vb >> vx;
793 gasfile >> alpha >> alpha0 >> eta;
803 for (
int l = 0; l < 6; l++) gasfile >> dif[l];
805 const unsigned int nexc = rexc.size();
806 for (
unsigned int l = 0; l < nexc; ++l) gasfile >> rexc[l];
808 const unsigned int nion = rion.size();
809 for (
unsigned int l = 0; l < nion; ++l) gasfile >> rion[l];
813 double& ve,
double& vb,
double& vx,
double& dl,
double& dt,
814 double& alpha,
double& alpha0,
double& eta,
double& mu,
double& lor,
815 double& dis, std::array<double, 6>& dif,
816 std::vector<double>& rexc, std::vector<double>& rion) {
819 gasfile >> ve >> waste >> vb >> waste >> vx >> waste;
823 gasfile >> dl >> waste >> dt >> waste;
824 gasfile >> alpha >> waste >> alpha0 >> eta >> waste;
825 gasfile >> mu >> waste;
827 gasfile >> lor >> waste;
828 gasfile >> dis >> waste;
829 for (
int j = 0; j < 6; j++) gasfile >> dif[j] >> waste;
830 const unsigned int nexc = rexc.size();
831 for (
unsigned int j = 0; j < nexc; ++j) gasfile >> rexc[j] >> waste;
832 const unsigned int nion = rion.size();
833 for (
unsigned int j = 0; j < nion; ++j) gasfile >> rion[j] >> waste;
837 std::array<unsigned int, 13>& extrapH,
838 std::array<unsigned int, 13>& extrapL,
839 std::array<unsigned int, 13>& interp,
840 unsigned int& thrAlp,
unsigned int& thrAtt,
unsigned int& thrDis,
841 double& ionDiffL,
double& ionDiffT,
842 double& pgas,
double& tgas) {
847 gasfile.getline(line, 256);
848 char* token = strtok(line,
" :,%=\t");
850 if (strcmp(token,
"H") == 0) {
851 token = strtok(NULL,
" :,%=\t");
852 for (
int i = 0; i < 13; i++) {
853 token = strtok(NULL,
" :,%=\t");
854 if (token != NULL) extrapH[i] = atoi(token);
856 }
else if (strcmp(token,
"L") == 0) {
857 token = strtok(NULL,
" :,%=\t");
858 for (
int i = 0; i < 13; i++) {
859 token = strtok(NULL,
" :,%=\t");
860 if (token != NULL) extrapL[i] = atoi(token);
862 }
else if (strcmp(token,
"Thresholds") == 0) {
863 token = strtok(NULL,
" :,%=\t");
864 if (token != NULL) thrAlp = atoi(token);
865 token = strtok(NULL,
" :,%=\t");
866 if (token != NULL) thrAtt = atoi(token);
867 token = strtok(NULL,
" :,%=\t");
868 if (token != NULL) thrDis = atoi(token);
869 }
else if (strcmp(token,
"Interp") == 0) {
870 for (
int i = 0; i < 13; i++) {
871 token = strtok(NULL,
" :,%=\t");
872 if (token != NULL) interp[i] = atoi(token);
874 }
else if (strcmp(token,
"A") == 0) {
876 token = strtok(NULL,
" :,%=\t");
877 }
else if (strcmp(token,
"Z") == 0) {
879 token = strtok(NULL,
" :,%=\t");
880 }
else if (strcmp(token,
"EMPROB") == 0) {
882 token = strtok(NULL,
" :,%=\t");
883 }
else if (strcmp(token,
"EPAIR") == 0) {
885 token = strtok(NULL,
" :,%=\t");
886 }
else if (strcmp(token,
"Ion") == 0) {
888 token = strtok(NULL,
" :,%=\t");
889 token = strtok(NULL,
" :,%=\t");
890 if (token != NULL) ionDiffL = atof(token);
891 token = strtok(NULL,
" :,%=\t");
892 if (token != NULL) ionDiffT = atof(token);
893 }
else if (strcmp(token,
"CMEAN") == 0) {
895 token = strtok(NULL,
" :,%=\t");
896 }
else if (strcmp(token,
"RHO") == 0) {
898 token = strtok(NULL,
" :,%=\t");
899 }
else if (strcmp(token,
"PGAS") == 0) {
901 token = strtok(NULL,
" :,%=\t");
902 if (token != NULL) pgas = atof(token);
903 }
else if (strcmp(token,
"TGAS") == 0) {
905 token = strtok(NULL,
" :,%=\t");
906 if (token != NULL) tgas = atof(token);
913 token = strtok(NULL,
" :,%=\t");
919 const int version, std::vector<std::string>& gasnames,
920 std::vector<double>& percentages)
const {
924 const unsigned int nMagboltzGases = mixture.size();
925 for (
unsigned int i = 0; i < nMagboltzGases; ++i) {
926 if (mixture[i] < Small)
continue;
927 const std::string gasname =
GetGasName(i + 1, version);
928 if (gasname.empty()) {
930 <<
" Unknown gas (gas number " << i + 1 <<
").\n";
933 gasnames.push_back(gasname);
934 percentages.push_back(mixture[i]);
938 <<
" Gas mixture has " << gasnames.size() <<
" components.\n"
939 <<
" Number of gases is limited to " <<
m_nMaxGases <<
".\n";
941 }
else if (gasnames.empty()) {
943 <<
" Gas mixture is not defined (zero components).\n";
946 double sum = std::accumulate(percentages.begin(), percentages.end(), 0.);
949 <<
" Renormalizing the percentages.\n";
950 for (
auto& percentage : percentages) percentage *= 100. / sum;
956 const bool replaceOld) {
963 constexpr double eps = 1.e-3;
965 std::ifstream gasfile(filename);
969 <<
" Cannot open file " << filename <<
".\n";
974 std::bitset<20> gasok;
976 constexpr int nMagboltzGases = 60;
977 std::vector<double> mixture(nMagboltzGases, 0.);
978 std::vector<double> efields;
979 std::vector<double> bfields;
980 std::vector<double> angles;
981 std::vector<ExcLevel> excLevels;
982 std::vector<IonLevel> ionLevels;
983 if (!
ReadHeader(gasfile, version, gasok, new3d, mixture, efields, bfields,
984 angles, excLevels, ionLevels)) {
985 std::cerr <<
m_className <<
"::MergeGasFile: Error reading header.\n";
992 <<
"This dataset cannot be read because of a change in format.\n";
998 std::vector<std::string> gasnames;
999 std::vector<double> percentages;
1000 if (!
GetMixture(mixture, version, gasnames, percentages)) {
1002 <<
"Cannot determine the gas composition.\n";
1008 <<
"Composition of the dataset differs from the present one.\n";
1014 const auto it = std::find(gasnames.begin(), gasnames.end(),
m_gas[i]);
1015 if (it == gasnames.end()) {
1017 <<
"Composition of the dataset differs from the present one.\n";
1022 const double f1 = 0.01 * percentages[it - gasnames.begin()];
1023 if (fabs(f1 - f2) > 1.e-6 * (1. + fabs(f1) + fabs(f2))) {
1025 <<
"Percentages of " <<
m_gas[i] <<
" differ.\n";
1032 const unsigned int nexc = excLevels.size();
1033 const unsigned int nion = ionLevels.size();
1036 for (
unsigned int i = 0; i < nexc; ++i) {
1037 if (
m_excLevels[i].label == excLevels[i].label)
continue;
1044 for (
unsigned int i = 0; i < nion; ++i) {
1045 if (
m_ionLevels[i].label == ionLevels[i].label)
continue;
1052 double ve = 0., vb = 0., vx = 0.;
1056 double dl = 0., dt = 0.;
1058 double alpha = 0., alpha0 = 0., eta = 0.;
1060 double mu = 0., dis = 0.;
1062 std::array<double, 6> diff;
1064 std::vector<double> rexc(nexc, 0.);
1065 std::vector<double> rion(nion, 0.);
1067 const unsigned int nNewE = efields.size();
1068 const unsigned int nNewB = bfields.size();
1069 const unsigned int nNewA = angles.size();
1070 for (
unsigned int i = 0; i < nNewE; i++) {
1071 for (
unsigned int j = 0; j < nNewA; j++) {
1072 for (
unsigned int k = 0; k < nNewB; k++) {
1074 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1075 lor, dis, diff, rexc, rion);
1077 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1078 lor, dis, diff, rexc, rion);
1085 std::array<unsigned int, 13> extrapH = {{0}};
1086 std::array<unsigned int, 13> extrapL = {{1}};
1088 std::array<unsigned int, 13> interp = {{2}};
1090 unsigned int thrAlp = 0, thrAtt = 0, thrDis = 0;
1092 double ionDiffL = 0., ionDiffT = 0.;
1094 double pgas = 0., tgas = 0.;
1096 gasfile.ignore(std::numeric_limits<std::streamsize>::max(),
'\n');
1097 ReadFooter(gasfile, extrapH, extrapL, interp, thrAlp, thrAtt, thrDis,
1098 ionDiffL, ionDiffT, pgas, tgas);
1103 <<
"The gas pressure of the dataset to be read differs\n "
1104 <<
"from the current reference pressure; stop.\n";
1110 <<
"The gas temperature of the dataset to be read differs\n "
1111 <<
"from the current reference temperature; stop.\n";
1119 if (!
ReadHeader(gasfile, version, gasok, new3d, mixture, efields, bfields,
1120 angles, excLevels, ionLevels)) {
1121 std::cerr <<
m_className <<
"::MergeGasFile: Error re-reading header.\n";
1127 for (
auto& field : efields) field *= pgas;
1131 <<
"Dataset to be merged has the following dimensions:\n "
1132 <<
"3D = " << new3d <<
" nE = " << nNewE <<
", nB = " << nNewB
1133 <<
", nA = " << nNewA <<
", nExc = "
1134 << excLevels.size() <<
", nIon = " << ionLevels.size() <<
"\n";
1141 const int iemode = Equal(efields,
m_eFields, eps);
1143 const int iamode = Equal(angles,
m_bAngles, eps);
1145 const int ibmode = Equal(bfields,
m_bFields, eps);
1148 if (iemode == 0) std::cout <<
" The E vectors differ.\n";
1149 else std::cout <<
" The E vectors are identical.\n";
1150 if (iamode == 0) std::cout <<
" The angle vectors differ.\n";
1151 else std::cout <<
" The angle vectors are identical.\n";
1152 if (ibmode == 0) std::cout <<
" The B vectors differ.\n";
1153 else std::cout <<
" The B vectors are identical.\n";
1156 if (iemode + iamode + ibmode < 2) {
1157 std::cerr <<
m_className <<
"::MergeGasFile:\n Existing data and data "
1158 <<
"in the file don't have two common axes; not merged.\n";
1164 if ((new3d || ibmode * iamode == 0) && !
m_tab2d) {
1165 if (
m_debug) std::cout <<
" Expanding existing table to 3D mode.\n";
1170 std::bitset<20> existing;
1173 if (iemode * ibmode * iamode == 0) {
1175 if (existing[0] && !gasok[0]) {
1178 PrintAbsentInNew(
"drift velocity");
1180 if (existing[1] && !gasok[1]) {
1183 PrintAbsentInNew(
"ion mobility");
1185 if (existing[2] && !gasok[2]) {
1188 PrintAbsentInNew(
"longitudinal diffusion");
1190 if (existing[3] && !gasok[3]) {
1193 PrintAbsentInNew(
"Townsend coefficient");
1195 if (existing[5] && !gasok[5]) {
1198 PrintAbsentInNew(
"attachment coefficient");
1200 if (existing[6] && !gasok[6]) {
1203 PrintAbsentInNew(
"Lorentz angle");
1205 if (existing[7] && !gasok[7]) {
1208 PrintAbsentInNew(
"transverse diffusion");
1210 if (existing[8] && !gasok[8]) {
1213 PrintAbsentInNew(
"velocity along Bt");
1215 if (existing[9] && !gasok[9]) {
1218 PrintAbsentInNew(
"velocity along ExB");
1220 if (existing[10] && !gasok[10]) {
1223 PrintAbsentInNew(
"diffusion tensor");
1225 if (existing[11] && !gasok[11]) {
1228 PrintAbsentInNew(
"ion dissociation data");
1230 if (existing[14] && !gasok[14]) {
1234 PrintAbsentInNew(
"excitation data");
1236 if (existing[15] && !gasok[15]) {
1240 PrintAbsentInNew(
"ionisation data");
1243 if (!existing[0] && gasok[0]) {
1245 PrintAbsentInExisting(
"drift velocity");
1247 if (!existing[1] && gasok[1]) {
1249 PrintAbsentInExisting(
"ion mobility");
1251 if (!existing[2] && gasok[2]) {
1253 PrintAbsentInExisting(
"longitudinal diffusion");
1255 if (!existing[3] && gasok[3]) {
1257 PrintAbsentInExisting(
"Townsend coefficient");
1259 if (!existing[5] && gasok[5]) {
1261 PrintAbsentInExisting(
"attachment coefficient");
1263 if (!existing[6] && gasok[6]) {
1266 PrintAbsentInExisting(
"Lorentz angle");
1273 if (!existing[7] && gasok[7]) {
1275 PrintAbsentInExisting(
"transverse diffusion");
1277 if (!existing[8] && gasok[8]) {
1280 PrintAbsentInExisting(
"velocity along Bt");
1287 if (!existing[9] && gasok[9]) {
1290 PrintAbsentInExisting(
"velocity along ExB");
1297 if (!existing[10] && gasok[10]) {
1299 PrintAbsentInExisting(
"diffusion tensor");
1301 if (!existing[11] && gasok[11]) {
1303 PrintAbsentInExisting(
"ion dissociation data");
1305 if (!existing[14] && gasok[14]) {
1307 PrintAbsentInExisting(
"excitation data");
1309 if (!existing[15] && gasok[15]) {
1311 PrintAbsentInExisting(
"ionisation data");
1313 if (existing[14] && gasok[14] && !excMatch) {
1314 std::cerr <<
" Excitation levels of the two datasets don't match.\n"
1315 <<
" Deleting excitation data.\n";
1321 if (existing[15] && gasok[15] && !ionMatch) {
1322 std::cerr <<
" Ionisation levels of the two datasets don't match.\n"
1323 <<
" Deleting ionisation data.\n";
1332 if (gasok[0] && !existing[0])
Init(nE, nB, nA,
m_eVelE, 0.);
1333 if (gasok[1] && !existing[1])
Init(nE, nB, nA,
m_iMob, 0.);
1334 if (gasok[2] && !existing[2])
Init(nE, nB, nA,
m_eDifL, 0.);
1335 if (gasok[3] && !existing[3]) {
1339 if (gasok[5] && !existing[5])
Init(nE, nB, nA,
m_eAtt, -30.);
1340 if (gasok[6] && !existing[6])
Init(nE, nB, nA,
m_eLor, -30.);
1341 if (gasok[7] && !existing[7])
Init(nE, nB, nA,
m_eDifT, 0.);
1342 if (gasok[8] && !existing[8])
Init(nE, nB, nA,
m_eVelB, 0.);
1343 if (gasok[9] && !existing[9])
Init(nE, nB, nA,
m_eVelX, 0.);
1344 if (gasok[10] && !existing[10])
Init(nE, nB, nA, 6,
m_eDifM, 0.);
1345 if (gasok[11] && !existing[11])
Init(nE, nB, nA,
m_iDis, -30.);
1346 if (gasok[14] && (!existing[14] || replaceOld)) {
1349 if (gasok[15] && (!existing[15] || replaceOld)) {
1355 std::vector<bool> newE(nE,
false);
1356 std::vector<bool> newA(nA,
false);
1357 std::vector<bool> newB(nB,
false);
1359 std::cout <<
m_className <<
"::MergeGasFile: Extending the tables.\n";
1363 for (
const auto efield : efields) {
1366 for (
unsigned int j = 0; j < nE; ++j) {
1368 if (Similar(efield,
m_eFields[j], eps)) {
1370 std::cout <<
" Replacing existing data for E = "
1371 <<
m_eFields[j] <<
" V/cm by data from file.\n";
1376 std::cout <<
" Keeping existing data for E = " <<
m_eFields[j]
1377 <<
" V/cm, not using data from the file.\n";
1384 std::cout <<
" Inserting E = " << efield
1385 <<
" V/cm at slot " << j <<
".\n";
1389 newE.insert(newE.begin() + j,
true);
1396 if (found)
continue;
1399 std::cout <<
" Adding E = " << efield <<
" V/cm at the end.\n";
1403 newE.push_back(
true);
1411 for (
const auto bfield : bfields) {
1414 for (
unsigned int j = 0; j < nB; ++j) {
1416 if (Similar(bfield,
m_bFields[j], eps)) {
1418 std::cout <<
" Replacing old data for B = " <<
m_bFields[j]
1419 <<
" T by data from file.\n";
1424 std::cout <<
" Keeping old data for B = " <<
m_bFields[j]
1425 <<
" T, not using data from file.\n";
1432 std::cout <<
" Inserting B = " << bfield <<
" T at slot "
1437 newB.insert(newB.begin() + j,
true);
1444 if (found)
continue;
1447 std::cout <<
" Adding B = " << bfield <<
" T at the end.\n";
1451 newB.push_back(
true);
1459 for (
const auto angle : angles) {
1462 for (
unsigned int j = 0; j < nA; ++j) {
1464 if (Similar(angle,
m_bAngles[j], eps)) {
1466 std::cout <<
" Replacing old data for angle(E,B) = "
1468 <<
" degrees by data from the file.\n";
1473 std::cout <<
" Keeping old data for angle(E,B) = "
1475 <<
" degrees, not using data from file.\n";
1482 std::cout <<
" Inserting angle = " << angle * RadToDegree
1483 <<
" degrees at slot " << j <<
".\n";
1487 newA.insert(newA.begin() + j,
true);
1494 if (found)
continue;
1497 std::cout <<
" Adding angle = " << angle * RadToDegree
1498 <<
" degrees at the end.\n";
1502 newA.push_back(
true);
1508 const double sqrp = sqrt(pgas);
1509 const double logp = log(pgas);
1512 for (
const auto efield : efields) {
1514 const int inde = FindIndex(efield,
m_eFields, eps);
1515 for (
const auto angle : angles) {
1516 const int inda = FindIndex(angle,
m_bAngles, eps);
1517 for (
const auto bfield : bfields) {
1520 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1521 lor, dis, diff, rexc, rion);
1523 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1524 lor, dis, diff, rexc, rion);
1526 const int indb = FindIndex(bfield,
m_bFields, eps);
1527 if (inde < 0 || inda < 0 || indb < 0) {
1528 std::cerr <<
m_className <<
"::MergeGasFile:\n Unable to locate"
1529 <<
" the (E,angle,B) insertion point; no gas data read.\n";
1530 std::cout <<
"BFIELD = " << bfield <<
", IB = " << indb <<
"\n";
1535 const bool update = newE[inde] || newA[inda] || newB[indb] || replaceOld;
1537 if (gasok[0] && (update || !existing[0])) {
1538 m_eVelE[inda][indb][inde] = ve;
1540 if (gasok[1] && (update || !existing[1])) {
1541 m_iMob[inda][indb][inde] = mu;
1543 if (gasok[2] && (update || !existing[2])) {
1544 m_eDifL[inda][indb][inde] = dl / sqrp;
1546 if (gasok[3] && (update || !existing[3])) {
1547 m_eAlp[inda][indb][inde] = alpha + logp;
1548 m_eAlp0[inda][indb][inde] = alpha0 + logp;
1550 if (gasok[5] && (update || !existing[5])) {
1551 m_eAtt[inda][indb][inde] = eta + logp;
1553 if (gasok[6] && (update || !existing[6])) {
1554 m_eLor[inda][indb][inde] = lor;
1556 if (gasok[7] && (update || !existing[7])) {
1557 m_eDifT[inda][indb][inde] = dt / sqrp;
1559 if (gasok[8] && (update || !existing[8])) {
1560 m_eVelB[inda][indb][inde] = vb;
1562 if (gasok[9] && (update || !existing[9])) {
1563 m_eVelX[inda][indb][inde] = vx;
1565 if (gasok[10] && (update || !existing[10])) {
1566 for (
unsigned int l = 0; l < 6; ++l) {
1567 m_eDifM[l][inda][indb][inde] = diff[l] / pgas;
1570 if (gasok[11] && (update || !existing[11])) {
1571 m_iDis[inda][indb][inde] = dis + logp;
1573 if (gasok[14] && (update || !existing[14])) {
1574 for (
unsigned int l = 0; l < nexc; ++l) {
1578 if (gasok[15] && (update || !existing[15])) {
1579 for (
unsigned int l = 0; l < nion; ++l) {
1590 <<
"Replacing extrapolation and interpolation data.\n";
1592 if (gasok[0])
m_extrVel = {extrapL[0], extrapH[0]};
1593 if (gasok[1])
m_extrMob = {extrapL[6], extrapH[6]};
1594 if (gasok[2])
m_extrDif = {extrapL[3], extrapH[3]};
1595 if (gasok[3])
m_extrAlp = {extrapL[4], extrapH[4]};
1596 if (gasok[5])
m_extrAtt = {extrapL[5], extrapH[5]};
1597 if (gasok[6])
m_extrLor = {extrapL[7], extrapH[7]};
1598 if (gasok[11])
m_extrDis = {extrapL[9], extrapH[9]};
1599 if (gasok[14])
m_extrExc = {extrapL[11], extrapH[11]};
1600 if (gasok[15])
m_extrIon = {extrapL[12], extrapH[12]};
1613 if (
m_debug && (ionDiffL > 0. || ionDiffT > 0.)) {
1614 std::cout <<
m_className <<
"::MergeGasFile: Replacing ion diffusion.\n";
1616 if (ionDiffL > 0.)
Init(nE, nB, nA,
m_iDifL, ionDiffL);
1617 if (ionDiffT > 0.)
Init(nE, nB, nA,
m_iDifT, ionDiffT);
1627 for (
int k = 0; k < na; ++k) {
1628 for (
int j = 0; j < nb; ++j) {
1642 for (
auto& dif :
m_eDifM) dif[k][j].resize(ne + 1, 0.);
1643 for (
auto& exc :
m_excRates) exc[k][j].resize(ne + 1, 0.);
1644 for (
auto& ion :
m_ionRates) ion[k][j].resize(ne + 1, 0.);
1645 for (
int i = ne; i > ie; --i) {
1659 for (
auto& dif :
m_eDifM) dif[k][j][i] = dif[k][j][i - 1];
1660 for (
auto& exc :
m_excRates) exc[k][j][i] = exc[k][j][i - 1];
1661 for (
auto& ion :
m_ionRates) ion[k][j][i] = ion[k][j][i - 1];
1669 for (
int k = 0; k < na; ++k) {
1670 if (!
m_eVelE.empty())
m_eVelE[k].resize(nb + 1, std::vector<double>(ne, 0.));
1671 if (!
m_eVelB.empty())
m_eVelB[k].resize(nb + 1, std::vector<double>(ne, 0.));
1672 if (!
m_eVelX.empty())
m_eVelX[k].resize(nb + 1, std::vector<double>(ne, 0.));
1673 if (!
m_eDifL.empty())
m_eDifL[k].resize(nb + 1, std::vector<double>(ne, 0.));
1674 if (!
m_eDifT.empty())
m_eDifT[k].resize(nb + 1, std::vector<double>(ne, 0.));
1675 if (!
m_eAlp.empty())
m_eAlp[k].resize(nb + 1, std::vector<double>(ne, 0.));
1676 if (!
m_eAlp0.empty())
m_eAlp0[k].resize(nb + 1, std::vector<double>(ne, 0.));
1677 if (!
m_eAtt.empty())
m_eAtt[k].resize(nb + 1, std::vector<double>(ne, 0.));
1678 if (!
m_eLor.empty())
m_eLor[k].resize(nb + 1, std::vector<double>(ne, 0.));
1679 if (!
m_iMob.empty())
m_iMob[k].resize(nb + 1, std::vector<double>(ne, 0.));
1680 if (!
m_iDis.empty())
m_iDis[k].resize(nb + 1, std::vector<double>(ne, 0.));
1681 if (!
m_iDifL.empty())
m_iDifL[k].resize(nb + 1, std::vector<double>(ne, 0.));
1682 if (!
m_iDifT.empty())
m_iDifT[k].resize(nb + 1, std::vector<double>(ne, 0.));
1684 dif[k].resize(nb + 1, std::vector<double>(ne, 0.));
1687 exc[k].resize(nb + 1, std::vector<double>(ne, 0.));
1690 ion[k].resize(nb + 1, std::vector<double>(ne, 0.));
1692 for (
int i = 0; i < ne; ++i) {
1693 for (
int j = nb; j > ib; j--) {
1707 for (
auto& dif :
m_eDifM) dif[k][j][i] = dif[k][j - 1][i];
1708 for (
auto& exc :
m_excRates) exc[k][j][i] = exc[k][j - 1][i];
1709 for (
auto& ion :
m_ionRates) ion[k][j][i] = ion[k][j - 1][i];
1717 ResizeA(
m_eVelE, ne, nb, na + 1);
1718 ResizeA(
m_eVelB, ne, nb, na + 1);
1719 ResizeA(
m_eVelX, ne, nb, na + 1);
1720 ResizeA(
m_eDifL, ne, nb, na + 1);
1721 ResizeA(
m_eDifT, ne, nb, na + 1);
1722 ResizeA(
m_eAlp, ne, nb, na + 1);
1723 ResizeA(
m_eAlp0, ne, nb, na + 1);
1724 ResizeA(
m_eAtt, ne, nb, na + 1);
1725 ResizeA(
m_eLor, ne, nb, na + 1);
1726 ResizeA(
m_iMob, ne, nb, na + 1);
1727 ResizeA(
m_iDis, ne, nb, na + 1);
1728 ResizeA(
m_iDifL, ne, nb, na + 1);
1729 ResizeA(
m_iDifT, ne, nb, na + 1);
1730 for (
auto& dif :
m_eDifM) ResizeA(dif, ne, nb, na + 1);
1731 for (
auto& exc :
m_excRates) ResizeA(exc, ne, nb, na + 1);
1732 for (
auto& ion :
m_ionRates) ResizeA(ion, ne, nb, na + 1);
1733 for (
int j = 0; j < nb; ++j) {
1734 for (
int i = 0; i < ne; ++i) {
1735 for (
int k = na; k > ia; k--) {
1749 for (
auto& dif :
m_eDifM) dif[k][j][i] = dif[k - 1][j][i];
1750 for (
auto& exc :
m_excRates) exc[k][j][i] = exc[k - 1][j][i];
1751 for (
auto& ion :
m_ionRates) ion[k][j][i] = ion[k - 1][j][i];
1758 for (
int k = 0; k < na; ++k) {
1759 for (
int j = 0; j < nb; ++j) {
1766 for (
int k = 0; k < na; ++k) {
1767 for (
int i = 0; i < ne; ++i) {
1774 for (
int j = 0; j < nb; ++j) {
1775 for (
int i = 0; i < ne; ++i) {
1788 constexpr int nMagboltzGases = 60;
1789 std::vector<double> mixture(nMagboltzGases, 0.);
1794 <<
" Error retrieving gas number for " <<
m_gas[i] <<
".\n";
1802 <<
" Writing gas tables to file " << filename <<
"\n";
1805 std::ofstream outfile(filename, std::ios::out);
1808 <<
" Cannot open file " << filename <<
".\n";
1814 std::bitset<20> gasok;
1816 std::string okstr(20,
'F');
1817 for (
unsigned int i = 0; i < 20; ++i) {
1818 if (gasok[i]) okstr[i] =
'T';
1820 if (
m_debug) std::cout <<
" GASOK bits: " << okstr <<
"\n";
1822 time_t rawtime = time(0);
1823 tm timeinfo = *localtime(&rawtime);
1824 char datebuf[80] = {0};
1825 char timebuf[80] = {0};
1827 strftime(datebuf,
sizeof(datebuf) - 1,
"%d/%m/%y", &timeinfo);
1828 strftime(timebuf,
sizeof(timebuf) - 1,
"%H.%M.%S", &timeinfo);
1830 std::string member =
"< none >";
1832 outfile <<
"*----.----1----.----2----.----3----.----4----.----"
1833 <<
"5----.----6----.----7----.----8----.----9----.---"
1834 <<
"10----.---11----.---12----.---13--\n";
1835 outfile <<
"% Created " << datebuf <<
" at " << timebuf <<
" ";
1836 outfile << member <<
" GAS ";
1839 outfile <<
"\"none" << std::string(25,
' ') <<
"\"\n";
1840 const int version = 12;
1841 outfile <<
" Version : " << version <<
"\n";
1842 outfile <<
" GASOK bits: " << okstr <<
"\n";
1843 std::stringstream ids(
"");
1849 outfile <<
" Identifier: " << std::setw(80) << std::left << ids.str() <<
"\n";
1850 outfile <<
" Clusters : " << std::string(80,
' ') <<
"\n";
1851 outfile <<
" Dimension : ";
1858 const unsigned int nE =
m_eFields.size();
1859 const unsigned int nB =
m_bFields.size();
1860 const unsigned int nA =
m_bAngles.size();
1863 <<
"Dataset has the following dimensions:\n "
1864 <<
"3D = " <<
m_tab2d <<
" nE = " << nE <<
", nB = " << nB
1865 <<
", nA = " << nA <<
", nExc = "
1868 outfile << FmtInt(nE, 9) <<
" " << FmtInt(nA, 9) <<
" "
1869 << FmtInt(nB, 9) <<
" " << FmtInt(
m_excLevels.size(), 9) <<
" "
1872 outfile <<
" E fields \n";
1873 std::vector<double> efields =
m_eFields;
1877 PrintArray(efields, outfile, cnt, 5);
1878 if (nE % 5 != 0) outfile <<
"\n";
1880 outfile <<
" E-B angles \n";
1883 if (nA % 5 != 0) outfile <<
"\n";
1885 outfile <<
" B fields \n";
1886 std::vector<double> bfields =
m_bFields;
1887 for (
auto& field : bfields) field *= 100.;
1889 PrintArray(bfields, outfile, cnt, 5);
1890 if (nB % 5 != 0) outfile <<
"\n";
1893 outfile <<
" Mixture: \n";
1895 PrintArray(mixture, outfile, cnt, 5);
1896 if (nMagboltzGases % 5 != 0) outfile <<
"\n";
1901 outfile <<
" Excitation " << FmtInt(cnt, 5) <<
": " << std::setw(45);
1903 if (exc.label.find(
" ") != std::string::npos) {
1904 outfile <<
"\"" + exc.label +
"\"";
1906 outfile << exc.label;
1908 outfile <<
" " << FmtFloat(exc.energy) << FmtFloat(exc.prob)
1909 << FmtFloat(exc.rms) << FmtFloat(exc.dt) <<
"\n";
1914 outfile <<
" Ionisation " << FmtInt(cnt, 5) <<
": " << std::setw(45);
1916 if (ion.label.find(
" ") != std::string::npos) {
1917 outfile <<
"\"" + ion.label <<
"\"";
1919 outfile << ion.label;
1921 outfile <<
" " << FmtFloat(ion.energy) <<
"\n";
1926 outfile <<
" The gas tables follow:\n";
1928 for (
unsigned int i = 0; i < nE; ++i) {
1929 for (
unsigned int j = 0; j < nA; ++j) {
1930 for (
unsigned int k = 0; k < nB; ++k) {
1940 std::vector<double> val;
1945 val = {ve, 0., vb, 0., vx, 0.};
1951 double alpha =
m_eAlp.empty() ? -30. :
m_eAlp[j][k][i] - logp;
1952 double alpha0 =
m_eAlp0.empty() ? -30. :
m_eAlp0[j][k][i] - logp;
1953 double eta =
m_eAtt.empty() ? -30. :
m_eAtt[j][k][i] - logp;
1956 val.insert(val.end(), {dl, dt, alpha, alpha0, eta});
1958 val.insert(val.end(), {dl, 0., dt, 0., alpha, 0., alpha0, eta, 0.});
1961 double mu =
m_iMob.empty() ? 0. : 1.e3 *
m_iMob[j][k][i];
1965 double diss =
m_iDis.empty() ? -30. :
m_iDis[j][k][i] - logp;
1968 val.insert(val.end(), {mu, lor, diss});
1970 val.insert(val.end(), {mu, 0., lor, 0., diss, 0.});
1973 for (
int l = 0; l < 6; ++l) {
1980 if (!
m_tab2d) val.push_back(0.);
1984 if (rexc[j][k][i] > Small) {
1985 val.push_back(rexc[j][k][i]);
1989 if (!
m_tab2d) val.push_back(0.);
1992 if (rion[j][k][i] > Small) {
1993 val.push_back(rion[j][k][i]);
1997 if (!
m_tab2d) val.push_back(0.);
1999 PrintArray(val, outfile, cnt, 8);
2001 if (cnt % 8 != 0) outfile <<
"\n";
2008 int extrapH[13], extrapL[13];
2009 extrapL[0] = extrapL[1] = extrapL[2] =
m_extrVel.first;
2010 extrapH[0] = extrapH[1] = extrapH[2] =
m_extrVel.second;
2011 extrapL[3] = extrapL[8] = extrapL[10] =
m_extrDif.first;
2012 extrapH[3] = extrapH[8] = extrapH[10] =
m_extrDif.second;
2028 outfile <<
" H Extr: ";
2029 for (
int i = 0; i < 13; i++) outfile << FmtInt(extrapH[i], 5);
2031 outfile <<
" L Extr: ";
2032 for (
int i = 0; i < 13; i++) outfile << FmtInt(extrapL[i], 5);
2036 outfile <<
" Thresholds: " << FmtInt(
m_eThrAlp + 1, 10)
2040 interp[0] = interp[1] = interp[2] =
m_intpVel;
2041 interp[3] = interp[8] = interp[10] =
m_intpDif;
2049 outfile <<
" Interp: ";
2050 for (
int i = 0; i < 13; i++) outfile << FmtInt(interp[i], 5);
2052 outfile <<
" A =" << FmtFloat(0.) <<
", Z =" << FmtFloat(0.) <<
","
2053 <<
" EMPROB=" << FmtFloat(0.) <<
", EPAIR =" << FmtFloat(0.) <<
"\n";
2056 outfile <<
" Ion diffusion: " << FmtFloat(dli) << FmtFloat(dti) <<
"\n";
2057 outfile <<
" CMEAN =" << FmtFloat(0.) <<
", RHO =" << FmtFloat(0.) <<
","
2060 outfile <<
" CLSTYP : NOT SET \n"
2061 <<
" FCNCLS : " << std::string(80,
' ') <<
"\n"
2062 <<
" NCLS : " << FmtInt(0, 10) <<
"\n"
2063 <<
" Average : " << FmtFloat(0., 25, 18) <<
"\n"
2064 <<
" Heed initialisation done: F\n"
2065 <<
" SRIM initialisation done: F\n";
2074 if (!
m_eVelE.empty()) gasok.set(0);
2075 if (!
m_iMob.empty()) gasok.set(1);
2076 if (!
m_eDifL.empty()) gasok.set(2);
2077 if (!
m_eAlp.empty()) gasok.set(3);
2079 if (!
m_eAtt.empty()) gasok.set(5);
2080 if (!
m_eLor.empty()) gasok.set(6);
2081 if (!
m_eDifT.empty()) gasok.set(7);
2082 if (!
m_eVelB.empty()) gasok.set(8);
2083 if (!
m_eVelX.empty()) gasok.set(9);
2084 if (!
m_eDifM.empty()) gasok.set(10);
2085 if (!
m_iDis.empty()) gasok.set(11);
2094 <<
" Gas composition: " <<
m_name;
2103 std::cout <<
" Pressure: " <<
m_pressure <<
" Torr\n"
2109 std::cout <<
" Electric field range: " <<
m_eFields[0] <<
" - "
2113 std::cout <<
" Electric field: " <<
m_eFields[0] <<
" V/cm\n";
2115 std::cout <<
" Electric field range: not set\n";
2118 std::cout <<
" Magnetic field range: " <<
m_bFields[0] <<
" - "
2122 std::cout <<
" Magnetic field: " <<
m_bFields[0] <<
" T\n";
2124 std::cout <<
" Magnetic field range: not set\n";
2127 std::cout <<
" Angular range: " <<
m_bAngles[0] <<
" - "
2131 std::cout <<
" Angle between E and B: " <<
m_bAngles[0] <<
" rad\n";
2133 std::cout <<
" Angular range: not set\n";
2136 std::cout <<
" Available electron transport data:\n";
2138 std::cout <<
" Velocity along E\n";
2141 std::cout <<
" Velocity along Bt\n";
2144 std::cout <<
" Velocity along ExB\n";
2149 std::cout <<
" Interpolation order: " <<
m_intpVel <<
"\n";
2152 std::cout <<
" Longitudinal diffusion coefficient\n";
2155 std::cout <<
" Transverse diffusion coefficient\n";
2158 std::cout <<
" Diffusion tensor\n";
2162 std::cout <<
" Interpolation order: " <<
m_intpDif <<
"\n";
2165 std::cout <<
" Townsend coefficient\n";
2167 std::cout <<
" Interpolation order: " <<
m_intpAlp <<
"\n";
2170 std::cout <<
" Attachment coefficient\n";
2172 std::cout <<
" Interpolation order: " <<
m_intpAtt <<
"\n";
2175 std::cout <<
" Lorentz Angle\n";
2177 std::cout <<
" Interpolation order: " <<
m_intpLor <<
"\n";
2180 std::cout <<
" Excitation rates\n";
2182 std::cout <<
" " << exc.label <<
"\n";
2183 std::cout <<
" Energy = " << exc.energy <<
" eV";
2184 if (exc.prob > 0.) {
2185 std::cout <<
", Penning transfer probability = " << exc.prob;
2190 std::cout <<
" Interpolation order: " <<
m_intpExc <<
"\n";
2193 std::cout <<
" Ionisation rates\n";
2195 std::cout <<
" " << ion.label <<
"\n";
2196 std::cout <<
" Threshold = " << ion.energy <<
" eV\n";
2199 std::cout <<
" Interpolation order: " <<
m_intpIon <<
"\n";
2205 std::cout <<
" none\n";
2208 std::cout <<
" Available ion transport data:\n";
2210 std::cout <<
" Mobility\n";
2212 std::cout <<
" Interpolation order: " <<
m_intpMob <<
"\n";
2215 std::cout <<
" Longitudinal diffusion coefficient\n";
2218 std::cout <<
" Transverse diffusion coefficient\n";
2222 std::cout <<
" Interpolation order: " <<
m_intpDif <<
"\n";
2225 std::cout <<
" Dissociation coefficient\n";
2227 std::cout <<
" Interpolation order: " <<
m_intpDis <<
"\n";
2230 std::cout <<
" none\n";
2245 const bool quiet,
const bool negative) {
2247 std::ifstream infile(filename);
2251 <<
" Cannot open file " << filename <<
".\n";
2254 std::cout <<
m_className <<
"::LoadMobility: Opened " << filename
2255 <<
" for reading.\n";
2258 std::vector<std::pair<double, double> > data;
2261 for (std::string line; std::getline(infile, line);) {
2263 if (line.empty())
continue;
2267 if (words.size() < 2) {
2268 std::cout <<
m_className <<
"::LoadMobility: Skipping line "
2272 const double field = std::stod(words[0]);
2273 const double mu = std::stod(words[1]);
2275 std::cout <<
" E/N = " << field <<
" Td: mu = " << mu <<
" cm2/(Vs)\n";
2281 <<
" Negative electric field (line " << i <<
").\n";
2285 data.push_back(std::make_pair(field, mu));
2290 std::cerr <<
m_className <<
"::LoadMobility: No valid data found.\n";
2294 std::sort(data.begin(), data.end());
2299 const double scaleField = 1.e-17 * LoschmidtNumber * pr / tr;
2301 const double scaleMobility = 1.e-9 * tr / pr;
2303 const size_t ne = data.size();
2304 std::vector<double> efields(ne, 0.);
2305 std::vector<double> mobilities(ne, 0.);
2306 for (
size_t j = 0; j < ne; ++j) {
2308 efields[j] = data[j].first * scaleField;
2309 mobilities[j] = data[j].second * scaleMobility;
2313 <<
" Read " << ne <<
" values from file " << filename <<
"\n";
2332 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2333 <<
" Penning transfer probability for " <<
m_name
2334 <<
" is not implemented.\n";
2338 const double p =
m_pressure / AtmosphericPressure;
2340 auto itNe = std::find(
m_gas.cbegin(),
m_gas.cend(),
"Ne");
2341 auto itAr = std::find(
m_gas.cbegin(),
m_gas.cend(),
"Ar");
2342 auto itXe = std::find(
m_gas.cbegin(),
m_gas.cend(),
"Xe");
2344 auto itN2 = std::find(
m_gas.cbegin(),
m_gas.cend(),
"N2");
2345 auto itCO2 = std::find(
m_gas.cbegin(),
m_gas.cend(),
"CO2");
2347 auto itCH4 = std::find(
m_gas.cbegin(),
m_gas.cend(),
"CH4");
2348 auto itC2H2 = std::find(
m_gas.cbegin(),
m_gas.cend(),
"C2H2");
2349 auto itC2H6 = std::find(
m_gas.cbegin(),
m_gas.cend(),
"C2H6");
2350 auto itC3H8 = std::find(
m_gas.cbegin(),
m_gas.cend(),
"C3H8");
2351 auto itC4H10 = std::find(
m_gas.cbegin(),
m_gas.cend(),
"iC4H10");
2353 auto itTMA = std::find(
m_gas.cbegin(),
m_gas.cend(),
"TMA");
2356 std::string gas =
"";
2357 if (itAr !=
m_gas.cend() && itCO2 !=
m_gas.cend()) {
2359 const int iCO2 = std::distance(
m_gas.cbegin(), itCO2);
2361 if (fabs(p - 1.) < 1.e-3) {
2364 constexpr double a1 = 0.6643;
2365 constexpr double a2 = 0.0518;
2366 constexpr double a3 = 0.0028;
2367 rP = (a1 * cCO2 + a3) / (cCO2 + a2);
2370 constexpr double a1 = 0.627898;
2371 constexpr double a2 = 0.041394;
2372 constexpr double a3 = 0.004716;
2373 constexpr double a4 = 0.001562;
2374 constexpr double a5 = 0.002422;
2375 constexpr double a6 = 0.027115;
2376 const double pcCO2 = p * cCO2;
2377 const double pcAr = p * (1. - cCO2);
2378 rP = (a5 * pcAr * pcAr + a1 * pcCO2 + a4 * cCO2 + a3) /
2379 (a6 * pcAr * pcAr + pcCO2 + a2);
2381 }
else if (itAr !=
m_gas.cend() && itCH4 !=
m_gas.cend()) {
2383 constexpr double b1 = 0.1956;
2384 constexpr double b2 = 16.38;
2385 constexpr double b3 = 22.12;
2386 constexpr double b4 = 3.842;
2387 constexpr double b5 = 2.992;
2388 constexpr double b6 = b4;
2389 const int iCH4 = std::distance(
m_gas.cbegin(), itCH4);
2391 const double pcAr = p * (1. - cCH4);
2392 rP = (b4 * p * cCH4 + b1 * pcAr + b2 * cCH4 + b5) /
2393 (b6 * p * cCH4 + pcAr + b3);
2395 }
else if (itAr !=
m_gas.cend() && itC2H6 !=
m_gas.cend()) {
2399 const int iC2H6 = std::distance(
m_gas.cbegin(), itC2H6);
2401 if (fabs(c - 0.1) > 0.01 || fabs(p - 1.) > 1.e-3) {
2402 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2403 <<
" Using transfer probability";
2404 if (fabs(c - 0.1) > 0.01) std::cout <<
" for 10% C2H6";
2405 if (fabs(p - 1.) > 1.e-3) std::cout <<
" at atmospheric pressure";
2409 }
else if (itAr !=
m_gas.cend() && itC3H8 !=
m_gas.cend()) {
2410 constexpr double a1 = 0.4536;
2411 constexpr double a2 = 0.0035;
2412 const int iC3H8 = std::distance(
m_gas.cbegin(), itC3H8);
2414 rP = (a1 * cC3H8) / (cC3H8 + a2);
2415 if (fabs(p - 1.) > 1.e-3) {
2416 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2417 <<
" Using transfer probability at atmospheric pressure.\n";
2420 }
else if (itAr !=
m_gas.cend() && itC4H10 !=
m_gas.cend()) {
2424 const int iC4H10 = std::distance(
m_gas.cbegin(), itC4H10);
2426 if (fabs(c - 0.1) > 0.01 || fabs(p - 1.) > 1.e-3) {
2427 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2428 <<
" Using transfer probability";
2429 if (fabs(c - 0.1) > 0.01) std::cout <<
" for 10% iC4H10";
2430 if (fabs(p - 1.) > 1.e-3) std::cout <<
" at atmospheric pressure";
2434 }
else if (itAr !=
m_gas.cend() && itC2H2 !=
m_gas.cend()) {
2440 if (fabs(p - 1.) > 1.e-3) {
2441 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2442 <<
" Using transfer probability at atmospheric pressure.\n";
2445 }
else if (itAr !=
m_gas.cend() && itXe !=
m_gas.cend()) {
2447 constexpr double a1 = 1.248;
2448 constexpr double a2 = 0.039;
2449 constexpr double a3 = 0.008;
2450 constexpr double a4 = 0;
2451 const int iXe = std::distance(
m_gas.cbegin(), itXe);
2453 const double cAr = 1. - cXe;
2454 rP = (a1 * cXe + a3) / (a4 * cAr * cAr + cXe + a2);
2455 if (fabs(p - 1.) > 1.e-3) {
2456 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2457 <<
" Using transfer probability at atmospheric pressure.\n";
2460 }
else if (itNe !=
m_gas.cend() && itCO2 !=
m_gas.cend()) {
2462 constexpr double a1 = 0.71104;
2463 constexpr double a2 = 0.06323;
2464 constexpr double a3 = 0.03085;
2465 constexpr double a4 = 4.20089;
2466 constexpr double a5 = 0.07831;
2467 constexpr double a6 = 0.13235;
2468 constexpr double a7 = 1.47470;
2469 const int iCO2 = std::distance(
m_gas.cbegin(), itCO2);
2471 const double pcCO2 = p * cCO2;
2472 const double pcNe = p * (1.- cCO2);
2473 rP = (a5 * pcNe * pcNe + a7 * cCO2 * cCO2 + a1 * pcCO2 + a3) /
2474 (a6 * pcNe * pcNe + a4 * cCO2 * cCO2 + pcCO2 + a2);
2476 }
else if (itNe !=
m_gas.cend() && itN2 !=
m_gas.cend()) {
2478 constexpr double a1 = 0.55802;
2479 constexpr double a2 = 0.00514;
2480 constexpr double a3 = 0.00206;
2481 constexpr double a4 = 0.55385;
2482 constexpr double a5 = 0.01153;
2483 constexpr double a6 = 0.02073;
2484 constexpr double a7 = 0.01;
2485 const int iN2 = std::distance(
m_gas.cbegin(), itN2);
2487 const double pcNe = p * (1. - cN2);
2488 rP = (a5 * pcNe * pcNe + a7 * cN2 * cN2 + a1 * p * cN2 + a3) /
2489 (a6 * pcNe * pcNe + a4 * cN2 * cN2 + p * cN2 + a2);
2491 }
else if (itXe !=
m_gas.cend() && itTMA !=
m_gas.cend()) {
2493 constexpr double a1 = 0.2472;
2494 constexpr double a2 = 0.2372;
2495 constexpr double a3 = 0.0414;
2498 rP = (a1 * p + a3) / (p + a2);
2499 const int iTMA = std::distance(
m_gas.cbegin(), itTMA);
2501 if (fabs(cTMA - 0.05) > 0.002) {
2502 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2503 <<
" Using transfer probability for 5% TMA.\n";
2507 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2508 <<
" Penning transfer probability for " <<
m_name
2509 <<
" is not implemented.\n";
2512 rP = std::max(rP, 0.);
2517 const double lambda) {
2520 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2521 <<
" Transfer probability must be >= 0.\n";
2528 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2529 <<
" Global Penning transfer parameters set to:\n"
2535 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n Warning: present"
2536 <<
" gas table has no ionisation rates.\n Ignore this message "
2537 <<
"if you are using microscopic tracking only.\n";
2540 double minIonPot = -1.;
2542 if (minIonPot < 0.) {
2543 minIonPot = ion.energy;
2545 minIonPot = std::min(minIonPot, ion.energy);
2550 unsigned int nLevelsFound = 0;
2552 if (exc.energy < minIonPot)
continue;
2557 if (nLevelsFound > 0) {
2558 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2559 <<
" Updated transfer probabilities for " << nLevelsFound
2560 <<
" excitation rates.\n";
2563 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n Warning: present"
2564 <<
" gas table has no eligible excitation rates.\n Ignore this"
2565 <<
" message if you are using microscopic tracking only.\n";
2571 std::string gasname) {
2574 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2575 <<
" Transfer probability must be >= 0.\n";
2581 if (gasname.empty()) {
2582 std::cerr <<
m_className <<
"::EnablePenningTransfer: Unknown gas name.\n";
2589 if (
m_gas[i] == gasname) {
2598 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2599 <<
" Requested gas (" << gasname
2600 <<
") is not part of the present gas mixture.\n";
2606 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n Warning: present"
2607 <<
" gas table has no ionisation rates.\n Ignore this message"
2608 <<
" if you are using microscopic tracking only.\n";
2611 double minIonPot = -1.;
2613 if (minIonPot < 0.) {
2614 minIonPot = ion.energy;
2616 minIonPot = std::min(minIonPot, ion.energy);
2620 unsigned int nLevelsFound = 0;
2622 if (exc.energy < minIonPot)
continue;
2624 if (exc.label.find(gasname) != 0)
continue;
2629 if (nLevelsFound > 0) {
2630 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2631 <<
" Updated transfer probabilities for " << nLevelsFound
2632 <<
" " << gasname <<
" excitation rates.\n";
2635 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n Warning: present"
2636 <<
" gas table has no eligible excitation rates.\n Ignore this"
2637 <<
" message if you are using microscopic tracking only.\n";
2658 double& r,
double& lambda) {
2665 std::cerr <<
m_className <<
"::GetPenningTransfer: Unknown gas name.\n";
2669 if (
m_gas[i] == gas) {
2675 std::cerr <<
m_className <<
"::GetPenningTransfer: " << gasname
2676 <<
" is not part of the mixture.\n";
2681 double& energy)
const {
2683 std::cerr <<
m_className <<
"::GetIonisationLevel: Index out of range.\n";
2691 double& energy)
const {
2693 std::cerr <<
m_className <<
"::GetExcitationLevel: Index out of range.\n";
2701 const size_t ie,
const size_t ib,
2702 const size_t ia,
double& f)
const {
2704 std::cerr <<
m_className <<
"::GetElectronIonisationRate:\n"
2705 <<
" Level index out of range.\n";
2712 const size_t ie,
const size_t ib,
2713 const size_t ia,
double& f)
const {
2715 std::cerr <<
m_className <<
"::GetElectronExcitationRate:\n"
2716 <<
" Level index out of range.\n";
2726 if (gasname.empty()) {
2727 std::cerr <<
m_className <<
"::DisablePenningTransfer: Unknown gas name.\n";
2734 if (
m_gas[i] == gasname) {
2743 std::cerr <<
m_className <<
"::DisablePenningTransfer:\n"
2744 <<
" Requested gas (" << gasname
2745 <<
") is not part of the present gas mixture.\n";
2752 const auto pos = exc.label.find(
'-');
2753 if (pos == std::string::npos)
continue;
2754 if (
GetGasName(exc.label.substr(0, pos)) != gasname)
continue;
2770 std::cerr <<
m_className <<
"::AdjustTownsendCoefficient:\n "
2771 <<
"Present gas table does not include Townsend coefficients.\n";
2776 std::cerr <<
m_className <<
"::AdjustTownsendCoefficient:\n "
2777 <<
"Present gas table does not include excitation rates.\n";
2781 std::cerr <<
m_className <<
"::AdjustTownsendCoefficient:\n "
2782 <<
"Present gas table does not include ionisation rates.\n";
2785 const unsigned int nE =
m_eFields.size();
2786 const unsigned int nB =
m_bFields.size();
2787 const unsigned int nA =
m_bAngles.size();
2789 std::cout <<
m_className <<
"::AdjustTownsendCoefficient:\n"
2790 <<
" Entry Exc. Ion.\n";
2792 for (
unsigned int i = 0; i < nE; ++i) {
2793 for (
unsigned int j = 0; j < nA; ++j) {
2794 for (
unsigned int k = 0; k < nB; ++k) {
2798 rion += ion[j][k][i];
2803 for (
unsigned int ie = 0; ie < nexc; ++ie) {
2807 std::cout << FmtInt(i, 4) << FmtInt(j, 4) << FmtInt(k, 4)
2808 << FmtFloat(rexc, 12, 5) << FmtFloat(rion, 12, 5) <<
"\n";
2811 double alpha0 =
m_eAlp0[j][k][i];
2812 if (alpha0 < -20.) {
2817 double alpha1 = alpha0;
2818 if (rion > 0.) alpha1 *= (rexc + rion) / rion;
2829 double& w,
double& f) {
2836 if (gasname ==
"CF4") {
2837 a = 12.0107 + 4 * 18.9984032;
2842 }
else if (gasname ==
"Ar") {
2847 }
else if (gasname ==
"He") {
2852 }
else if (gasname ==
"He-3") {
2857 }
else if (gasname ==
"Ne") {
2862 }
else if (gasname ==
"Kr") {
2867 }
else if (gasname ==
"Xe") {
2872 }
else if (gasname ==
"CH4") {
2873 a = 12.0107 + 4 * 1.00794;
2877 }
else if (gasname ==
"C2H6") {
2878 a = 2 * 12.0107 + 6 * 1.00794;
2882 }
else if (gasname ==
"C3H8") {
2883 a = 3 * 12.0107 + 8 * 1.00794;
2887 }
else if (gasname ==
"iC4H10") {
2888 a = 4 * 12.0107 + 10 * 1.00794;
2892 }
else if (gasname ==
"CO2") {
2893 a = 12.0107 + 2 * 15.9994;
2897 }
else if (gasname ==
"neoC5H12") {
2898 a = 5 * 12.0107 + 12 * 1.00794;
2902 }
else if (gasname ==
"H2O") {
2903 a = 2 * 1.00794 + 15.9994;
2907 }
else if (gasname ==
"O2") {
2912 }
else if (gasname ==
"N2") {
2917 }
else if (gasname ==
"NO") {
2918 a = 14.0067 + 15.9994;
2922 }
else if (gasname ==
"N2O") {
2923 a = 2 * 14.0067 + 15.9994;
2927 }
else if (gasname ==
"C2H4") {
2928 a = 2 * 12.0107 + 4 * 1.00794;
2932 }
else if (gasname ==
"C2H2") {
2933 a = 2 * 12.0107 + 2 * 1.00794;
2937 }
else if (gasname ==
"H2" || gasname ==
"paraH2") {
2942 }
else if (gasname ==
"D2" || gasname ==
"orthoD2") {
2943 a = 2 * 2.01410177785;
2947 }
else if (gasname ==
"CO") {
2948 a = 12.0107 + 15.9994;
2952 }
else if (gasname ==
"Methylal") {
2953 a = 3 * 12.0107 + 8 * 1.00794 + 2 * 15.9994;
2954 z = 3 * 6 + 8 + 2 * 8;
2957 }
else if (gasname ==
"DME") {
2958 a = 4 * 12.0107 + 10 * 1.00794 + 2 * 15.9994;
2959 z = 4 * 6 + 10 + 2 * 8;
2963 }
else if (gasname ==
"Reid-Step" || gasname ==
"Maxwell-Model" ||
2964 gasname ==
"Reid-Ramp") {
2969 }
else if (gasname ==
"C2F6") {
2970 a = 2 * 12.0107 + 6 * 18.9984032;
2974 }
else if (gasname ==
"SF6") {
2975 a = 32.065 + 6 * 18.9984032;
2979 }
else if (gasname ==
"NH3") {
2980 a = 14.0067 + 3 * 1.00794;
2984 }
else if (gasname ==
"C3H6") {
2985 a = 3 * 12.0107 + 6 * 1.00794;
2989 }
else if (gasname ==
"cC3H6") {
2990 a = 3 * 12.0107 + 6 * 1.00794;
2994 }
else if (gasname ==
"CH3OH") {
2995 a = 12.0107 + 4 * 1.00794 + 15.9994;
2999 }
else if (gasname ==
"C2H5OH") {
3000 a = 2 * 12.0107 + 6 * 1.00794 + 15.9994;
3004 }
else if (gasname ==
"C3H7OH" || gasname ==
"nC3H7OH") {
3005 a = 3 * 12.0107 + 8 * 1.00794 + 15.9994;
3009 }
else if (gasname ==
"Cs") {
3014 }
else if (gasname ==
"F2") {
3020 }
else if (gasname ==
"CS2") {
3021 a = 12.0107 + 2 * 32.065;
3025 }
else if (gasname ==
"COS") {
3026 a = 12.0107 + 15.9994 + 32.065;
3031 }
else if (gasname ==
"CD4") {
3032 a = 12.0107 + 4 * 2.01410177785;
3036 }
else if (gasname ==
"BF3") {
3037 a = 10.811 + 3 * 18.9984032;
3041 }
else if (gasname ==
"C2H2F4") {
3042 a = 2 * 12.0107 + 2 * 1.00794 + 4 * 18.9984032;
3043 z = 2 * 6 + 2 + 4 * 9;
3047 }
else if (gasname ==
"CHF3") {
3048 a = 12.0107 + 1.00794 + 3 * 18.9984032;
3053 }
else if (gasname ==
"CF3Br") {
3054 a = 12.0107 + 3 * 18.9984032 + 79.904;
3059 }
else if (gasname ==
"C3F8") {
3060 a = 3 * 12.0107 + 8 * 18.9984032;
3064 }
else if (gasname ==
"O3") {
3070 }
else if (gasname ==
"Hg") {
3075 }
else if (gasname ==
"H2S") {
3076 a = 2 * 1.00794 + 32.065;
3080 }
else if (gasname ==
"nC4H10") {
3081 a = 4 * 12.0107 + 10 * 1.00794;
3085 }
else if (gasname ==
"nC5H12") {
3086 a = 5 * 12.0107 + 12 * 1.00794;
3090 }
else if (gasname ==
"GeH4") {
3091 a = 72.64 + 4 * 1.00794;
3096 }
else if (gasname ==
"SiH4") {
3097 a = 28.0855 + 4 * 1.00794;
3102 }
else if (gasname ==
"CCl4") {
3103 a = 12.0107 + 4 * 35.45;
3119 switch (gasnumber) {
3173 return "Maxwell-Model";
3207 return version <= 11 ?
"He-3" :
"TMA";
3209 return version <= 11 ?
"He" :
"paraH2";
3211 return version <= 11 ?
"Ne" :
"nC3H7OH";
3215 return version <= 11 ?
"Kr" :
"orthoD2";
3251 return {
"tetrafluoromethane",
"Freon",
"Freon-14"};
3252 }
else if (gas ==
"Ar") {
3254 }
else if (gas ==
"He") {
3255 return {
"helium",
"He-4",
"He 4",
"He4",
"4-He",
"4 He",
"4He",
3256 "helium-4",
"helium 4",
"helium4"};
3257 }
else if (gas ==
"He-3") {
3258 return {
"He3",
"He 3",
"3-He",
"3 He",
"3He",
3259 "helium-3",
"helium 3",
"helium3"};
3260 }
else if (gas ==
"Ne") {
3262 }
else if (gas ==
"Kr") {
3264 }
else if (gas ==
"Xe") {
3266 }
else if (gas ==
"CH4") {
3268 }
else if (gas ==
"C2H6") {
3270 }
else if (gas ==
"C3H8") {
3272 }
else if (gas ==
"iC4H10") {
3273 return {
"isobutane",
"iso-C4H10",
"isoC4H10",
"C4H10"};
3274 }
else if (gas ==
"CO2") {
3275 return {
"carbon-dioxide",
"carbon dioxide",
"carbondioxide"};
3276 }
else if (gas ==
"neoC5H12") {
3277 return {
"neopentane",
"neo-pentane",
"neo-C5H12",
"C5H12",
3278 "dimethylpropane",
"tetramethylmethane"};
3279 }
else if (gas ==
"H2O") {
3280 return {
"water",
"water-vapour",
"water vapour"};
3281 }
else if (gas ==
"O2") {
3283 }
else if (gas ==
"N2") {
3284 return {
"nitrogen"};
3285 }
else if (gas ==
"NO") {
3286 return {
"nitric-oxide",
"nitric oxide",
3287 "nitrogen-monoxide",
"nitrogen monoxide"};
3288 }
else if (gas ==
"N2O") {
3289 return {
"nitrous-oxide",
"nitrous oxide",
"laughing-gas",
"laughing gas",
3290 "dinitrogen-monoxide",
"dinitrogen monoxide",
3291 "dinitrogen-oxide",
"dinitrogen oxide"};
3292 }
else if (gas ==
"C2H4") {
3293 return {
"ethene",
"ethylene"};
3294 }
else if (gas ==
"C2H2") {
3295 return {
"acetyl",
"acetylene",
"ethyne"};
3296 }
else if (gas ==
"H2") {
3297 return {
"hydrogen"};
3298 }
else if (gas ==
"paraH2") {
3299 return {
"para H2",
"para-H2",
"para hydrogen",
3300 "para-hydrogen",
"parahydrogen"};
3301 }
else if (gas ==
"D2") {
3302 return {
"deuterium"};
3303 }
else if (gas ==
"orthoD2") {
3304 return {
"ortho D2",
"ortho-D2",
"ortho deuterium",
3305 "ortho-deuterium",
"orthodeuterium"};
3306 }
else if (gas ==
"CO") {
3307 return {
"carbon-monoxide",
"carbon monoxide"};
3308 }
else if (gas ==
"Methylal") {
3309 return {
"methylal-hot",
"DMM",
"dimethoxymethane",
"Formal",
"C3H8O2"};
3310 }
else if (gas ==
"DME") {
3311 return {
"dimethyl-ether",
"dimethylether",
"dimethyl ether",
3312 "methyl-ether",
"methylether",
"methyl ether",
3313 "wood-ether",
"woodether",
"wood ether",
3314 "dimethyl oxide",
"dimethyl-oxide",
"Demeon",
3315 "methoxymethane",
"C4H10O2"};
3316 }
else if (gas ==
"Reid-Step") {
3318 }
else if (gas ==
"Maxwell-Model") {
3320 }
else if (gas ==
"Reid-Ramp") {
3322 }
else if (gas ==
"C2F6") {
3323 return {
"Freon-116",
"Zyron-116",
"Zyron-116-N5",
"hexafluoroethane"};
3324 }
else if (gas ==
"SF6") {
3325 return {
"sulphur-hexafluoride",
"sulfur-hexafluoride",
3326 "sulphur hexafluoride",
"sulfur hexafluoride"};
3327 }
else if (gas ==
"NH3") {
3328 return {
"ammonia",
"azane",
"R-717",
"R717"};
3329 }
else if (gas ==
"C3H6") {
3330 return {
"propene",
"propylene"};
3331 }
else if (gas ==
"cC3H6") {
3332 return {
"c-propane",
"cyclo-propane",
"cyclo propane",
"cyclopropane",
3333 "c-C3H6",
"cyclo-C3H6"};
3334 }
else if (gas ==
"CH3OH") {
3335 return {
"methanol",
"methyl-alcohol",
"methyl alcohol",
"wood alcohol",
3337 }
else if (gas ==
"C2H5OH") {
3338 return {
"ethanol",
"ethyl-alcohol",
"ethyl alcohol",
"grain alcohol",
3340 }
else if (gas ==
"C3H7OH") {
3341 return {
"propanol",
"2-propanol",
"isopropyl",
"iso-propanol",
3342 "isopropanol",
"isopropyl alcohol",
"isopropyl-alcohol"};
3343 }
else if (gas ==
"nC3H7OH") {
3344 return {
"npropanol",
"n-propanol",
"1-propanol",
"propyl alcohol",
3345 "propyl-alcohol",
"n-propyl alcohol",
"nC3H7OH",
"n-C3H7OH"};
3346 }
else if (gas ==
"Cs") {
3347 return {
"cesium",
"caesium"};
3348 }
else if (gas ==
"F2") {
3349 return {
"fluor",
"fluorine"};
3350 }
else if (gas ==
"CS2") {
3351 return {
"carbon-disulphide",
"carbon-disulfide",
3352 "carbon disulphide",
"carbon disulfide"};
3353 }
else if (gas ==
"COS") {
3354 return {
"carbonyl-sulphide",
"carbonyl-sulfide",
"carbonyl sulfide"};
3355 }
else if (gas ==
"CD4") {
3356 return {
"deut-methane",
"deuterium-methane",
"deuterated-methane",
3357 "deuterated methane",
"deuterium methane"};
3358 }
else if (gas ==
"BF3") {
3359 return {
"boron-trifluoride",
"boron trifluoride"};
3360 }
else if (gas ==
"C2H2F4") {
3361 return {
"C2HF5",
"C2F5H",
"C2F4H2",
"Freon 134",
"Freon 134A",
3362 "Freon-134",
"Freon-134-A",
"R-134a",
"R134a",
3363 "Freon 125",
"Freon-125",
"Zyron 125",
"Zyron-125",
3364 "tetrafluoroethane",
"pentafluoroethane",
"norflurane"};
3365 }
else if (gas ==
"TMA") {
3366 return {
"trimethylamine",
"N(CH3)3",
"N-(CH3)3"};
3367 }
else if (gas ==
"CHF3") {
3368 return {
"Freon-23",
"trifluoromethane",
"Fluoroform"};
3369 }
else if (gas ==
"CF3Br") {
3370 return {
"CBrF3",
"trifluorobromomethane",
"bromotrifluoromethane",
3371 "Halon-1301",
"Halon 1301",
"Freon-13B1",
"Freon 13BI"};
3372 }
else if (gas ==
"C3F8") {
3373 return {
"octafluoropropane",
"R218",
"R-218",
"Freon 218",
"Freon-218",
3374 "perfluoropropane",
"RC 218",
"PFC 218",
3375 "RC-218",
"PFC-218",
"Flutec PP30",
"Genetron 218"};
3376 }
else if (gas ==
"O3") {
3378 }
else if (gas ==
"Hg") {
3379 return {
"mercury",
"Hg2"};
3380 }
else if (gas ==
"H2S") {
3381 return {
"hydrogen sulphide",
"hydrogen-sulphide",
3382 "hydrogen sulfide",
"hydrogen-sulfide",
3383 "sewer gas",
"sewer-gas",
"hepatic acid",
"hepatic-acid",
3384 "sulfur hydride",
"sulfur-hydride",
3385 "dihydrogen monosulfide",
"dihydrogen-monosulfide",
3386 "dihydrogen monosulphide",
"dihydrogen-monosulphide",
3387 "sulphur hydride",
"sulphur-hydride",
"stink damp",
"stink-damp",
3388 "sulfurated hydrogen",
"sulfurated-hydrogen"};
3389 }
else if (gas ==
"nC4H10") {
3390 return {
"n-butane",
"n-C4H10",
"nbutane"};
3391 }
else if (gas ==
"nC5H12") {
3392 return {
"n-pentane",
"n-C5H12",
"npentane"};
3393 }
else if (gas ==
"N2 (Phelps)") {
3394 return {
"nitrogen-Phelps",
"nitrogen Phelps",
"N2-Phelps",
"N2 Phelps"};
3395 }
else if (gas ==
"GeH4") {
3396 return {
"germane",
"germanium-hydride",
"germanium hydride",
3397 "germanium tetrahydride",
"germanium-tetrahydride",
3398 "germanomethane",
"monogermane"};
3399 }
else if (gas ==
"SiH4") {
3400 return {
"silane",
"silicon-hydride",
"silicon hydride",
3401 "silicon-tetrahydride",
"silicane",
"monosilane"};
3402 }
else if (gas ==
"CCl4") {
3403 return {
"carbon tetrachloride",
"carbon-tetrachloride",
3404 "Benziform",
"tetrachloromethane",
"carbon tet",
3405 "Halon 104",
"Halon-104",
"Freon 10",
"Freon-10"};
3412 constexpr int version = 12;
3413 std::cout <<
"MediumGas::PrintGases:\n"
3414 <<
"Gas Aliases\n" << std::string(80,
'-') <<
"\n";
3415 for (
int i = 1; i <= 61; ++i) {
3416 if (i == 47)
continue;
3417 const std::string gas = i == 58 ?
"N2 (Phelps)" :
GetGasName(i, version);
3418 if (gas.empty())
continue;
3419 std::cout << std::setw(15) << std::left << gas;
3422 for (
auto it = aliases.cbegin(); it != aliases.cend(); ++it) {
3423 const auto alias = (*it);
3424 if (count + alias.size() > 63) {
3425 std::cout <<
"\n" << std::string(15,
' ');
3429 count += alias.size();
3430 if (std::next(it) != aliases.cend()) {
3441 std::transform(input.begin(), input.end(), input.begin(), toupper);
3442 if (input.empty())
return "";
3445 for (
int i = 1; i <= 61; ++i) {
3446 const std::string gas = i == 58 ?
"N2 (Phelps)" :
GetGasName(i, 12);
3447 if (gas.empty())
continue;
3449 std::string tmp = gas;
3450 std::transform(tmp.begin(), tmp.end(), tmp.begin(), toupper);
3451 if (tmp == input)
return gas;
3453 for (
const auto& alias : aliases) {
3455 std::transform(tmp.begin(), tmp.end(), tmp.begin(), toupper);
3456 if (tmp == input)
return gas;
3464 if (input.empty())
return 0;
3466 if (input ==
"CF4") {
3468 }
else if (input ==
"Ar") {
3470 }
else if (input ==
"He" || input ==
"He-4") {
3472 }
else if (input ==
"He-3") {
3474 }
else if (input ==
"Ne") {
3476 }
else if (input ==
"Kr") {
3478 }
else if (input ==
"Xe") {
3480 }
else if (input ==
"CH4") {
3483 }
else if (input ==
"C2H6") {
3486 }
else if (input ==
"C3H8") {
3489 }
else if (input ==
"iC4H10") {
3492 }
else if (input ==
"CO2") {
3494 }
else if (input ==
"neoC5H12") {
3497 }
else if (input ==
"H2O") {
3499 }
else if (input ==
"O2") {
3501 }
else if (input ==
"N2") {
3503 }
else if (input ==
"NO") {
3506 }
else if (input ==
"N2O") {
3509 }
else if (input ==
"C2H4") {
3512 }
else if (input ==
"C2H2") {
3515 }
else if (input ==
"H2") {
3517 }
else if (input ==
"D2") {
3520 }
else if (input ==
"CO") {
3522 }
else if (input ==
"Methylal") {
3525 }
else if (input ==
"DME") {
3527 }
else if (input ==
"Reid-Step") {
3529 }
else if (input ==
"Maxwell-Model") {
3531 }
else if (input ==
"Reid-Ramp") {
3533 }
else if (input ==
"C2F6") {
3535 }
else if (input ==
"SF6") {
3537 }
else if (input ==
"NH3") {
3539 }
else if (input ==
"C3H6") {
3542 }
else if (input ==
"cC3H6") {
3545 }
else if (input ==
"CH3OH") {
3548 }
else if (input ==
"C2H5OH") {
3551 }
else if (input ==
"C3H7OH") {
3554 }
else if (input ==
"Cs") {
3556 }
else if (input ==
"F2") {
3559 }
else if (input ==
"CS2") {
3561 }
else if (input ==
"COS") {
3563 }
else if (input ==
"CD4") {
3566 }
else if (input ==
"BF3") {
3568 }
else if (input ==
"C2HF5" || input ==
"C2H2F4") {
3570 }
else if (input ==
"TMA") {
3572 }
else if (input ==
"paraH2") {
3574 }
else if (input ==
"nC3H7OH") {
3576 }
else if (input ==
"orthoD2") {
3578 }
else if (input ==
"CHF3") {
3580 }
else if (input ==
"CF3Br") {
3582 }
else if (input ==
"C3F8") {
3584 }
else if (input ==
"O3") {
3587 }
else if (input ==
"Hg") {
3589 }
else if (input ==
"H2S") {
3591 }
else if (input ==
"nC4H10") {
3594 }
else if (input ==
"nC5H12") {
3597 }
else if (input ==
"N2 (Phelps)") {
3599 }
else if (input ==
"GeH4") {
3602 }
else if (input ==
"SiH4") {
3605 }
else if (input ==
"CCl4") {
3612 const unsigned int i) {
3615 <<
"::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 LoadGasFile(const std::string &filename, const bool quiet=false)
Read table of gas properties (transport parameters) from file.
bool AdjustTownsendCoefficient()
bool GetElectronIonisationRate(const size_t level, const size_t ie, const size_t ib, const size_t ia, double &f) const
Get an entry in the table of ionisation rates.
void GetIonisationLevel(const size_t level, std::string &label, double &energy) const
Return the identifier and threshold of an ionisation level.
std::pair< unsigned int, unsigned int > m_extrIon
bool GetPenningTransfer(const std::string &gasname, double &r, double &lambda)
void SetAtomicNumber(const double z) override
Set the effective atomic number.
bool LoadNegativeIonMobility(const std::string &filename, const bool quiet=false)
Read a table of negative ion mobilities vs. electric field from file.
virtual bool EnablePenningTransfer()
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
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) const
Retrieve the gas mixture.
double GetAtomicNumber() const override
Get the effective atomic number.
std::array< double, m_nMaxGases > m_atNum
static void PrintGases()
Print a list of all available gases.
void GetGasBits(std::bitset< 20 > &gasok) const
static const std::vector< std::string > GetAliases(const std::string &gas)
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.
bool LoadMobility(const std::string &filename, const bool quiet, const bool negative)
std::vector< ExcLevel > m_excLevels
void ZeroRowB(const int ib, const int ne, const int na)
bool GetElectronExcitationRate(const size_t level, const size_t ie, const size_t ib, const size_t ia, double &f) const
Get an entry in the table of excitation rates.
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
bool LoadIonMobility(const std::string &filename, const bool quiet=false)
Read a table of (positive) ion mobilities vs. electric field from file.
static int GetGasNumberGasFile(const std::string &input)
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)
static bool GetGasInfo(const std::string &gasname, double &a, double &z, double &w, double &f)
std::array< double, m_nMaxGases > m_atWeight
static std::string GetGasName(const int gasnumber, const int version)
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.
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].
std::vector< std::vector< std::vector< double > > > m_eAlp0
void GetExcitationLevel(const size_t level, std::string &label, double &energy) const
Return the identifier and energy of an excitation level.
void InsertA(const int ia, const int ne, const int nb, const int na)
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
std::vector< double > m_bFields
bool GetEntry(const size_t i, const size_t j, const size_t k, const std::string &fcn, const std::vector< std::vector< std::vector< double > > > &tab, double &val) const
std::vector< std::vector< std::vector< double > > > m_eAlp
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
size_t SetThreshold(const std::vector< std::vector< std::vector< double > > > &tab) const
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
bool SetIonMobility(const std::vector< double > &fields, const std::vector< double > &mobilities, const bool negativeIons=false)
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
static bool IsAvailable(const std::string &material)
Check whether optical data have been implemented for a given gas.
static bool PhotoabsorptionCrossSection(const std::string &material, const double energy, double &cs, double &eta)
Photo-absorption cross-section and ionisation yield at a given energy.
std::vector< std::string > tokenize(const std::string &line)
bool startsWith(const std::string &line, const std::string &s)
DoubleAc fabs(const DoubleAc &f)