21std::string FmtFloat(
const double x,
const unsigned int width = 15,
22 const unsigned int precision = 8) {
24 std::snprintf(buffer, width + 1,
"%*.*E", width, precision, x);
25 return std::string(buffer);
28std::string FmtInt(
const int n,
const unsigned int width) {
30 std::snprintf(buffer, width + 1,
"%*d", width, n);
31 return std::string(buffer);
34void PrintArray(
const std::vector<double>& values, std::ofstream& outfile,
35 int& col,
const int ncols) {
36 for (
const auto value : values) {
37 outfile << FmtFloat(value);
39 if (col % ncols == 0) outfile <<
"\n";
43void PrintExtrapolation(
const std::pair<unsigned int, unsigned int>& extr) {
44 std::cout <<
" Low field extrapolation: ";
46 std::cout <<
" constant\n";
47 else if (extr.first == 1)
48 std::cout <<
" linear\n";
49 else if (extr.first == 2)
50 std::cout <<
" exponential\n";
52 std::cout <<
" unknown\n";
53 std::cout <<
" High field extrapolation: ";
55 std::cout <<
" constant\n";
56 else if (extr.second == 1)
57 std::cout <<
" linear\n";
58 else if (extr.second == 2)
59 std::cout <<
" exponential\n";
61 std::cout <<
" unknown\n";
64void PrintAbsentInNew(
const std::string& par) {
65 std::cout <<
" Warning: The " << par <<
" is absent in the dataset "
66 <<
"to be added; data reset.\n";
69void PrintAbsentInExisting(
const std::string& par) {
70 std::cout <<
" Warning: The " << par <<
" is absent in the existing data; "
71 <<
"new data not used.\n";
74bool Similar(
const double v1,
const double v2,
const double eps) {
75 const double dif = v1 - v2;
76 const double sum =
fabs(v1) +
fabs(v2);
77 return fabs(dif) < std::max(eps * sum, Garfield::Small);
80int Equal(
const std::vector<double>& fields1,
81 const std::vector<double>& fields2,
const double eps) {
82 if (fields1.size() != fields2.size())
return 0;
83 const size_t n = fields1.size();
84 for (
size_t i = 0; i < n; ++i) {
85 if (!Similar(fields1[i], fields2[i], eps))
return 0;
90int FindIndex(
const double field,
const std::vector<double>& fields,
93 const int n = fields.size();
94 for (
int i = 0; i < n; ++i) {
95 if (Similar(field, fields[i], eps))
return i;
100void ResizeA(std::vector<std::vector<std::vector<double> > >& tab,
101 const int ne,
const int nb,
const int na) {
102 if (tab.empty())
return;
104 std::vector<std::vector<double> >(nb,
105 std::vector<double>(ne, 0.)));
113 :
Medium(), m_pressureTable(m_pressure), m_temperatureTable(m_temperature) {
136 const std::string& gas2,
const double f2,
137 const std::string& gas3,
const double f3,
138 const std::string& gas4,
const double f4,
139 const std::string& gas5,
const double f5,
140 const std::string& gas6,
const double f6) {
141 std::array<std::string, 6> gases = {gas1, gas2, gas3, gas4, gas5, gas6};
142 std::array<double, 6> fractions = {f1, f2, f3, f4, f5, f6};
145 const std::array<std::string, m_nMaxGases> gasOld =
m_gas;
158 for (
unsigned int i = 0; i < 6; ++i) {
159 if (fractions[i] < Small)
continue;
161 const std::string gasname =
GetGasName(gases[i]);
162 if (!gasname.empty()) {
172 <<
" Error setting the composition. No valid components.\n";
207 std::array<double, m_nMaxGases> rPenningGasOld;
208 std::array<double, m_nMaxGases> lambdaPenningGasOld;
209 rPenningGasOld.fill(0.);
210 lambdaPenningGasOld.fill(0.);
214 for (
unsigned int j = 0; j < nComponentsOld; ++j) {
215 if (
m_gas[i] != gasOld[j])
continue;
216 if (rPenningGasOld[j] < Small)
continue;
220 <<
" Using Penning transfer parameters for " <<
m_gas[i]
221 <<
" from previous mixture.\n"
230 double& f2, std::string& gas3,
double& f3,
231 std::string& gas4,
double& f4, std::string& gas5,
232 double& f5, std::string& gas6,
double& f6) {
250 std::cerr <<
m_className <<
"::GetComponent: Index out of range.\n";
262 <<
" Effective Z cannot be changed directly.\n"
263 <<
" Use SetComposition to define the gas mixture.\n";
268 <<
" Effective A cannot be changed directly.\n"
269 <<
" Use SetComposition to define the gas mixture.\n";
273 std::cerr <<
m_className <<
"::SetNumberDensity:\n"
274 <<
" Density cannot be changed directly.\n"
275 <<
" Use SetTemperature and SetPressure.\n";
280 <<
" Density cannot be changed directly.\n"
281 <<
" Use SetTemperature, SetPressure and SetComposition.\n";
295 return LoschmidtNumber * (
m_pressure / AtmosphericPressure) *
318 std::ifstream gasfile;
320 gasfile.open(filename.c_str());
322 if (!gasfile.is_open()) {
324 <<
" Cannot open file " << filename <<
".\n";
327 std::cout <<
m_className <<
"::LoadGasFile: Reading " << filename <<
".\n";
335 std::bitset<20> gasok;
337 constexpr int nMagboltzGases = 60;
338 std::vector<double> mixture(nMagboltzGases, 0.);
344 std::cout <<
m_className <<
"::LoadGasFile: Version " << version <<
"\n";
347 std::vector<std::string> gasnames;
348 std::vector<double> percentages;
349 if (!
GetMixture(mixture, version, gasnames, percentages)) {
351 <<
"Cannot determine the gas composition.\n";
361 m_gas[i] = gasnames[i];
366 <<
" Gas composition set to " <<
m_name;
380 std::cout <<
m_className <<
"::LoadGasFile:\n " << nE
381 <<
" electric field(s), " << nB
382 <<
" magnetic field(s), " << nA <<
" angle(s).\n";
417 if (gasok[11])
Init(nE, nB, nA,
m_iDis, -30.);
425 const std::string fmt =
m_tab2d ?
"3D" :
"1D";
426 std::cout <<
m_className <<
"::LoadGasFile: Reading " << fmt <<
" table.\n";
430 double ve = 0., vb = 0., vx = 0.;
434 double dl = 0., dt = 0.;
436 double alpha = 0., alpha0 = 0., eta = 0.;
438 double mu = 0., dis = 0.;
440 std::array<double, 6> diff;
443 std::vector<double> rexc(nexc, 0.);
445 std::vector<double> rion(nion, 0.);
446 for (
int i = 0; i < nE; i++) {
447 for (
int j = 0; j < nA; j++) {
448 for (
int k = 0; k < nB; k++) {
450 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
451 lor, dis, diff, rexc, rion);
453 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
454 lor, dis, diff, rexc, rion);
470 for (
int l = 0; l < 6; l++) {
475 for (
unsigned int l = 0; l < nexc; ++l) {
480 for (
unsigned int l = 0; l < nion; ++l) {
489 std::array<unsigned int, 13> extrapH = {{0}};
490 std::array<unsigned int, 13> extrapL = {{1}};
492 std::array<unsigned int, 13> interp = {{2}};
494 double ionDiffL = 0.;
495 double ionDiffT = 0.;
500 gasfile.ignore(std::numeric_limits<std::streamsize>::max(),
'\n');
521 for (
int i = nE; i--;) {
522 for (
int j = nA; j--;) {
523 for (
int k = nB; k--;) {
571 if (ionDiffL > 0.)
Init(nE, nB, nA,
m_iDifL, ionDiffL);
572 if (ionDiffT > 0.)
Init(nE, nB, nA,
m_iDifT, ionDiffT);
580 std::bitset<20>& gasok,
bool& is3d, std::vector<double>& mixture,
581 std::vector<double>& efields, std::vector<double>& bfields,
582 std::vector<double>& angles, std::vector<ExcLevel>& excLevels,
583 std::vector<IonLevel>& ionLevels) {
588 while (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) {
853 token = strtok(NULL,
" :,%=\t");
854 }
else if (strcmp(token,
"Z") == 0) {
856 token = strtok(NULL,
" :,%=\t");
857 }
else if (strcmp(token,
"EMPROB") == 0) {
859 token = strtok(NULL,
" :,%=\t");
860 }
else if (strcmp(token,
"EPAIR") == 0) {
862 token = strtok(NULL,
" :,%=\t");
863 }
else if (strcmp(token,
"Ion") == 0) {
865 token = strtok(NULL,
" :,%=\t");
866 token = strtok(NULL,
" :,%=\t");
867 if (token != NULL) ionDiffL = atof(token);
868 token = strtok(NULL,
" :,%=\t");
869 if (token != NULL) ionDiffT = atof(token);
870 }
else if (strcmp(token,
"CMEAN") == 0) {
872 token = strtok(NULL,
" :,%=\t");
873 }
else if (strcmp(token,
"RHO") == 0) {
875 token = strtok(NULL,
" :,%=\t");
876 }
else if (strcmp(token,
"PGAS") == 0) {
878 token = strtok(NULL,
" :,%=\t");
879 if (token != NULL) pgas = atof(token);
880 }
else if (strcmp(token,
"TGAS") == 0) {
882 token = strtok(NULL,
" :,%=\t");
883 if (token != NULL) tgas = atof(token);
890 token = strtok(NULL,
" :,%=\t");
896 const int version, std::vector<std::string>& gasnames,
897 std::vector<double>& percentages)
const {
901 const unsigned int nMagboltzGases = mixture.size();
902 for (
unsigned int i = 0; i < nMagboltzGases; ++i) {
903 if (mixture[i] < Small)
continue;
904 const std::string gasname =
GetGasName(i + 1, version);
905 if (gasname.empty()) {
907 <<
" Unknown gas (gas number " << i + 1 <<
").\n";
910 gasnames.push_back(gasname);
911 percentages.push_back(mixture[i]);
915 <<
" Gas mixture has " << gasnames.size() <<
" components.\n"
916 <<
" Number of gases is limited to " <<
m_nMaxGases <<
".\n";
918 }
else if (gasnames.empty()) {
920 <<
" Gas mixture is not defined (zero components).\n";
923 double sum = std::accumulate(percentages.begin(), percentages.end(), 0.);
926 <<
" Renormalizing the percentages.\n";
927 for (
auto& percentage : percentages) percentage *= 100. / sum;
933 const bool replaceOld) {
940 constexpr double eps = 1.e-3;
942 std::ifstream gasfile;
944 gasfile.open(filename.c_str());
946 if (!gasfile.is_open()) {
948 <<
" Cannot open file " << filename <<
".\n";
953 std::bitset<20> gasok;
955 constexpr int nMagboltzGases = 60;
956 std::vector<double> mixture(nMagboltzGases, 0.);
957 std::vector<double> efields;
958 std::vector<double> bfields;
959 std::vector<double> angles;
960 std::vector<ExcLevel> excLevels;
961 std::vector<IonLevel> ionLevels;
962 if (!
ReadHeader(gasfile, version, gasok, new3d, mixture, efields, bfields,
963 angles, excLevels, ionLevels)) {
964 std::cerr <<
m_className <<
"::MergeGasFile: Error reading header.\n";
971 <<
"This dataset cannot be read because of a change in format.\n";
977 std::vector<std::string> gasnames;
978 std::vector<double> percentages;
979 if (!
GetMixture(mixture, version, gasnames, percentages)) {
981 <<
"Cannot determine the gas composition.\n";
987 <<
"Composition of the dataset differs from the present one.\n";
993 const auto it = std::find(gasnames.begin(), gasnames.end(),
m_gas[i]);
994 if (it == gasnames.end()) {
996 <<
"Composition of the dataset differs from the present one.\n";
1001 const double f1 = 0.01 * percentages[it - gasnames.begin()];
1002 if (fabs(f1 - f2) > 1.e-6 * (1. + fabs(f1) + fabs(f2))) {
1004 <<
"Percentages of " <<
m_gas[i] <<
" differ.\n";
1011 const unsigned int nexc = excLevels.size();
1012 const unsigned int nion = ionLevels.size();
1015 for (
unsigned int i = 0; i < nexc; ++i) {
1016 if (
m_excLevels[i].label == excLevels[i].label)
continue;
1023 for (
unsigned int i = 0; i < nion; ++i) {
1024 if (
m_ionLevels[i].label == ionLevels[i].label)
continue;
1031 double ve = 0., vb = 0., vx = 0.;
1035 double dl = 0., dt = 0.;
1037 double alpha = 0., alpha0 = 0., eta = 0.;
1039 double mu = 0., dis = 0.;
1041 std::array<double, 6> diff;
1043 std::vector<double> rexc(nexc, 0.);
1044 std::vector<double> rion(nion, 0.);
1046 const unsigned int nNewE = efields.size();
1047 const unsigned int nNewB = bfields.size();
1048 const unsigned int nNewA = angles.size();
1049 for (
unsigned int i = 0; i < nNewE; i++) {
1050 for (
unsigned int j = 0; j < nNewA; j++) {
1051 for (
unsigned int k = 0; k < nNewB; k++) {
1053 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1054 lor, dis, diff, rexc, rion);
1056 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1057 lor, dis, diff, rexc, rion);
1064 std::array<unsigned int, 13> extrapH = {{0}};
1065 std::array<unsigned int, 13> extrapL = {{1}};
1067 std::array<unsigned int, 13> interp = {{2}};
1069 unsigned int thrAlp = 0, thrAtt = 0, thrDis = 0;
1071 double ionDiffL = 0., ionDiffT = 0.;
1073 double pgas = 0., tgas = 0.;
1075 gasfile.ignore(std::numeric_limits<std::streamsize>::max(),
'\n');
1076 ReadFooter(gasfile, extrapH, extrapL, interp, thrAlp, thrAtt, thrDis,
1077 ionDiffL, ionDiffT, pgas, tgas);
1082 <<
"The gas pressure of the dataset to be read differs\n "
1083 <<
"from the current reference pressure; stop.\n";
1089 <<
"The gas temperature of the dataset to be read differs\n "
1090 <<
"from the current reference temperature; stop.\n";
1098 if (!
ReadHeader(gasfile, version, gasok, new3d, mixture, efields, bfields,
1099 angles, excLevels, ionLevels)) {
1100 std::cerr <<
m_className <<
"::MergeGasFile: Error re-reading header.\n";
1106 for (
auto& field : efields) field *= pgas;
1110 <<
"Dataset to be merged has the following dimensions:\n "
1111 <<
"3D = " << new3d <<
" nE = " << nNewE <<
", nB = " << nNewB
1112 <<
", nA = " << nNewA <<
", nExc = "
1113 << excLevels.size() <<
", nIon = " << ionLevels.size() <<
"\n";
1120 const int iemode = Equal(efields,
m_eFields, eps);
1122 const int iamode = Equal(angles,
m_bAngles, eps);
1124 const int ibmode = Equal(bfields,
m_bFields, eps);
1127 if (iemode == 0) std::cout <<
" The E vectors differ.\n";
1128 else std::cout <<
" The E vectors are identical.\n";
1129 if (iamode == 0) std::cout <<
" The angle vectors differ.\n";
1130 else std::cout <<
" The angle vectors are identical.\n";
1131 if (ibmode == 0) std::cout <<
" The B vectors differ.\n";
1132 else std::cout <<
" The B vectors are identical.\n";
1135 if (iemode + iamode + ibmode < 2) {
1136 std::cerr <<
m_className <<
"::MergeGasFile:\n Existing data and data "
1137 <<
"in the file don't have two common axes; not merged.\n";
1143 if ((new3d || ibmode * iamode == 0) && !
m_tab2d) {
1144 if (
m_debug) std::cout <<
" Expanding existing table to 3D mode.\n";
1149 std::bitset<20> existing;
1152 if (iemode * ibmode * iamode == 0) {
1154 if (existing[0] && !gasok[0]) {
1157 PrintAbsentInNew(
"drift velocity");
1159 if (existing[1] && !gasok[1]) {
1162 PrintAbsentInNew(
"ion mobility");
1164 if (existing[2] && !gasok[2]) {
1167 PrintAbsentInNew(
"longitudinal diffusion");
1169 if (existing[3] && !gasok[3]) {
1172 PrintAbsentInNew(
"Townsend coefficient");
1174 if (existing[5] && !gasok[5]) {
1177 PrintAbsentInNew(
"attachment coefficient");
1179 if (existing[6] && !gasok[6]) {
1182 PrintAbsentInNew(
"Lorentz angle");
1184 if (existing[7] && !gasok[7]) {
1187 PrintAbsentInNew(
"transverse diffusion");
1189 if (existing[8] && !gasok[8]) {
1192 PrintAbsentInNew(
"velocity along Bt");
1194 if (existing[9] && !gasok[9]) {
1197 PrintAbsentInNew(
"velocity along ExB");
1199 if (existing[10] && !gasok[10]) {
1202 PrintAbsentInNew(
"diffusion tensor");
1204 if (existing[11] && !gasok[11]) {
1207 PrintAbsentInNew(
"ion dissociation data");
1209 if (existing[14] && !gasok[14]) {
1213 PrintAbsentInNew(
"excitation data");
1215 if (existing[15] && !gasok[15]) {
1219 PrintAbsentInNew(
"ionisation data");
1222 if (!existing[0] && gasok[0]) {
1224 PrintAbsentInExisting(
"drift velocity");
1226 if (!existing[1] && gasok[1]) {
1228 PrintAbsentInExisting(
"ion mobility");
1230 if (!existing[2] && gasok[2]) {
1232 PrintAbsentInExisting(
"longitudinal diffusion");
1234 if (!existing[3] && gasok[3]) {
1236 PrintAbsentInExisting(
"Townsend coefficient");
1238 if (!existing[5] && gasok[5]) {
1240 PrintAbsentInExisting(
"attachment coefficient");
1242 if (!existing[6] && gasok[6]) {
1245 PrintAbsentInExisting(
"Lorentz angle");
1252 if (!existing[7] && gasok[7]) {
1254 PrintAbsentInExisting(
"transverse diffusion");
1256 if (!existing[8] && gasok[8]) {
1259 PrintAbsentInExisting(
"velocity along Bt");
1266 if (!existing[9] && gasok[9]) {
1269 PrintAbsentInExisting(
"velocity along ExB");
1276 if (!existing[10] && gasok[10]) {
1278 PrintAbsentInExisting(
"diffusion tensor");
1280 if (!existing[11] && gasok[11]) {
1282 PrintAbsentInExisting(
"ion dissociation data");
1284 if (!existing[14] && gasok[14]) {
1286 PrintAbsentInExisting(
"excitation data");
1288 if (!existing[15] && gasok[15]) {
1290 PrintAbsentInExisting(
"ionisation data");
1292 if (existing[14] && gasok[14] && !excMatch) {
1293 std::cerr <<
" Excitation levels of the two datasets don't match.\n"
1294 <<
" Deleting excitation data.\n";
1300 if (existing[15] && gasok[15] && !ionMatch) {
1301 std::cerr <<
" Ionisation levels of the two datasets don't match.\n"
1302 <<
" Deleting ionisation data.\n";
1311 if (gasok[0] && !existing[0])
Init(nE, nB, nA,
m_eVelE, 0.);
1312 if (gasok[1] && !existing[1])
Init(nE, nB, nA,
m_iMob, 0.);
1313 if (gasok[2] && !existing[2])
Init(nE, nB, nA,
m_eDifL, 0.);
1314 if (gasok[3] && !existing[3]) {
1318 if (gasok[5] && !existing[5])
Init(nE, nB, nA,
m_eAtt, -30.);
1319 if (gasok[6] && !existing[6])
Init(nE, nB, nA,
m_eLor, -30.);
1320 if (gasok[7] && !existing[7])
Init(nE, nB, nA,
m_eDifT, 0.);
1321 if (gasok[8] && !existing[8])
Init(nE, nB, nA,
m_eVelB, 0.);
1322 if (gasok[9] && !existing[9])
Init(nE, nB, nA,
m_eVelX, 0.);
1323 if (gasok[10] && !existing[10])
Init(nE, nB, nA, 6,
m_eDifM, 0.);
1324 if (gasok[11] && !existing[11])
Init(nE, nB, nA,
m_iDis, -30.);
1325 if (gasok[14] && (!existing[14] || replaceOld)) {
1328 if (gasok[15] && (!existing[15] || replaceOld)) {
1334 std::vector<bool> newE(nE,
false);
1335 std::vector<bool> newA(nA,
false);
1336 std::vector<bool> newB(nB,
false);
1338 std::cout <<
m_className <<
"::MergeGasFile: Extending the tables.\n";
1342 for (
const auto efield : efields) {
1345 for (
unsigned int j = 0; j < nE; ++j) {
1347 if (Similar(efield,
m_eFields[j], eps)) {
1349 std::cout <<
" Replacing existing data for E = "
1350 <<
m_eFields[j] <<
" V/cm by data from file.\n";
1355 std::cout <<
" Keeping existing data for E = " <<
m_eFields[j]
1356 <<
" V/cm, not using data from the file.\n";
1363 std::cout <<
" Inserting E = " << efield
1364 <<
" V/cm at slot " << j <<
".\n";
1368 newE.insert(newE.begin() + j,
true);
1375 if (found)
continue;
1378 std::cout <<
" Adding E = " << efield <<
" V/cm at the end.\n";
1382 newE.push_back(
true);
1390 for (
const auto bfield : bfields) {
1393 for (
unsigned int j = 0; j < nB; ++j) {
1395 if (Similar(bfield,
m_bFields[j], eps)) {
1397 std::cout <<
" Replacing old data for B = " <<
m_bFields[j]
1398 <<
" T by data from file.\n";
1403 std::cout <<
" Keeping old data for B = " <<
m_bFields[j]
1404 <<
" T, not using data from file.\n";
1411 std::cout <<
" Inserting B = " << bfield <<
" T at slot "
1416 newB.insert(newB.begin() + j,
true);
1423 if (found)
continue;
1426 std::cout <<
" Adding B = " << bfield <<
" T at the end.\n";
1430 newB.push_back(
true);
1438 for (
const auto angle : angles) {
1441 for (
unsigned int j = 0; j < nA; ++j) {
1443 if (Similar(angle,
m_bAngles[j], eps)) {
1445 std::cout <<
" Replacing old data for angle(E,B) = "
1447 <<
" degrees by data from the file.\n";
1452 std::cout <<
" Keeping old data for angle(E,B) = "
1454 <<
" degrees, not using data from file.\n";
1461 std::cout <<
" Inserting angle = " << angle * RadToDegree
1462 <<
" degrees at slot " << j <<
".\n";
1466 newA.insert(newA.begin() + j,
true);
1473 if (found)
continue;
1476 std::cout <<
" Adding angle = " << angle * RadToDegree
1477 <<
" degrees at the end.\n";
1481 newA.push_back(
true);
1487 const double sqrp = sqrt(pgas);
1488 const double logp = log(pgas);
1491 for (
const auto efield : efields) {
1493 const int inde = FindIndex(efield,
m_eFields, eps);
1494 for (
const auto angle : angles) {
1495 const int inda = FindIndex(angle,
m_bAngles, eps);
1496 for (
const auto bfield : bfields) {
1499 ReadRecord3D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1500 lor, dis, diff, rexc, rion);
1502 ReadRecord1D(gasfile, ve, vb, vx, dl, dt, alpha, alpha0, eta, mu,
1503 lor, dis, diff, rexc, rion);
1505 const int indb = FindIndex(bfield,
m_bFields, eps);
1506 if (inde < 0 || inda < 0 || indb < 0) {
1507 std::cerr <<
m_className <<
"::MergeGasFile:\n Unable to locate"
1508 <<
" the (E,angle,B) insertion point; no gas data read.\n";
1509 std::cout <<
"BFIELD = " << bfield <<
", IB = " << indb <<
"\n";
1514 const bool update = newE[inde] || newA[inda] || newB[indb] || replaceOld;
1516 if (gasok[0] && (update || !existing[0])) {
1517 m_eVelE[inda][indb][inde] = ve;
1519 if (gasok[1] && (update || !existing[1])) {
1520 m_iMob[inda][indb][inde] = mu;
1522 if (gasok[2] && (update || !existing[2])) {
1523 m_eDifL[inda][indb][inde] = dl / sqrp;
1525 if (gasok[3] && (update || !existing[3])) {
1526 m_eAlp[inda][indb][inde] = alpha + logp;
1527 m_eAlp0[inda][indb][inde] = alpha0 + logp;
1529 if (gasok[5] && (update || !existing[5])) {
1530 m_eAtt[inda][indb][inde] = eta + logp;
1532 if (gasok[6] && (update || !existing[6])) {
1533 m_eLor[inda][indb][inde] = lor;
1535 if (gasok[7] && (update || !existing[7])) {
1536 m_eDifT[inda][indb][inde] = dt / sqrp;
1538 if (gasok[8] && (update || !existing[8])) {
1539 m_eVelB[inda][indb][inde] = vb;
1541 if (gasok[9] && (update || !existing[9])) {
1542 m_eVelX[inda][indb][inde] = vx;
1544 if (gasok[10] && (update || !existing[10])) {
1545 for (
unsigned int l = 0; l < 6; ++l) {
1546 m_eDifM[l][inda][indb][inde] = diff[l] / pgas;
1549 if (gasok[11] && (update || !existing[11])) {
1550 m_iDis[inda][indb][inde] = dis + logp;
1552 if (gasok[14] && (update || !existing[14])) {
1553 for (
unsigned int l = 0; l < nexc; ++l) {
1557 if (gasok[15] && (update || !existing[15])) {
1558 for (
unsigned int l = 0; l < nion; ++l) {
1569 <<
"Replacing extrapolation and interpolation data.\n";
1571 if (gasok[0])
m_extrVel = {extrapL[0], extrapH[0]};
1572 if (gasok[1])
m_extrMob = {extrapL[6], extrapH[6]};
1573 if (gasok[2])
m_extrDif = {extrapL[3], extrapH[3]};
1574 if (gasok[3])
m_extrAlp = {extrapL[4], extrapH[4]};
1575 if (gasok[5])
m_extrAtt = {extrapL[5], extrapH[5]};
1576 if (gasok[6])
m_extrLor = {extrapL[7], extrapH[7]};
1577 if (gasok[11])
m_extrDis = {extrapL[9], extrapH[9]};
1578 if (gasok[14])
m_extrExc = {extrapL[11], extrapH[11]};
1579 if (gasok[15])
m_extrIon = {extrapL[12], extrapH[12]};
1592 if (
m_debug && (ionDiffL > 0. || ionDiffT > 0.)) {
1593 std::cout <<
m_className <<
"::MergeGasFile: Replacing ion diffusion.\n";
1595 if (ionDiffL > 0.)
Init(nE, nB, nA,
m_iDifL, ionDiffL);
1596 if (ionDiffT > 0.)
Init(nE, nB, nA,
m_iDifT, ionDiffT);
1606 for (
int k = 0; k < na; ++k) {
1607 for (
int j = 0; j < nb; ++j) {
1621 for (
auto& dif :
m_eDifM) dif[k][j].resize(ne + 1, 0.);
1622 for (
auto& exc :
m_excRates) exc[k][j].resize(ne + 1, 0.);
1623 for (
auto& ion :
m_ionRates) ion[k][j].resize(ne + 1, 0.);
1624 for (
int i = ne; i > ie; --i) {
1638 for (
auto& dif :
m_eDifM) dif[k][j][i] = dif[k][j][i - 1];
1639 for (
auto& exc :
m_excRates) exc[k][j][i] = exc[k][j][i - 1];
1640 for (
auto& ion :
m_ionRates) ion[k][j][i] = ion[k][j][i - 1];
1648 for (
int k = 0; k < na; ++k) {
1649 if (!
m_eVelE.empty())
m_eVelE[k].resize(nb + 1, std::vector<double>(ne, 0.));
1650 if (!
m_eVelB.empty())
m_eVelB[k].resize(nb + 1, std::vector<double>(ne, 0.));
1651 if (!
m_eVelX.empty())
m_eVelX[k].resize(nb + 1, std::vector<double>(ne, 0.));
1652 if (!
m_eDifL.empty())
m_eDifL[k].resize(nb + 1, std::vector<double>(ne, 0.));
1653 if (!
m_eDifT.empty())
m_eDifT[k].resize(nb + 1, std::vector<double>(ne, 0.));
1654 if (!
m_eAlp.empty())
m_eAlp[k].resize(nb + 1, std::vector<double>(ne, 0.));
1655 if (!
m_eAlp0.empty())
m_eAlp0[k].resize(nb + 1, std::vector<double>(ne, 0.));
1656 if (!
m_eAtt.empty())
m_eAtt[k].resize(nb + 1, std::vector<double>(ne, 0.));
1657 if (!
m_eLor.empty())
m_eLor[k].resize(nb + 1, std::vector<double>(ne, 0.));
1658 if (!
m_iMob.empty())
m_iMob[k].resize(nb + 1, std::vector<double>(ne, 0.));
1659 if (!
m_iDis.empty())
m_iDis[k].resize(nb + 1, std::vector<double>(ne, 0.));
1660 if (!
m_iDifL.empty())
m_iDifL[k].resize(nb + 1, std::vector<double>(ne, 0.));
1661 if (!
m_iDifT.empty())
m_iDifT[k].resize(nb + 1, std::vector<double>(ne, 0.));
1663 dif[k].resize(nb + 1, std::vector<double>(ne, 0.));
1666 exc[k].resize(nb + 1, std::vector<double>(ne, 0.));
1669 ion[k].resize(nb + 1, std::vector<double>(ne, 0.));
1671 for (
int i = 0; i < ne; ++i) {
1672 for (
int j = nb; j > ib; j--) {
1686 for (
auto& dif :
m_eDifM) dif[k][j][i] = dif[k][j - 1][i];
1687 for (
auto& exc :
m_excRates) exc[k][j][i] = exc[k][j - 1][i];
1688 for (
auto& ion :
m_ionRates) ion[k][j][i] = ion[k][j - 1][i];
1696 ResizeA(
m_eVelE, ne, nb, na + 1);
1697 ResizeA(
m_eVelB, ne, nb, na + 1);
1698 ResizeA(
m_eVelX, ne, nb, na + 1);
1699 ResizeA(
m_eDifL, ne, nb, na + 1);
1700 ResizeA(
m_eDifT, ne, nb, na + 1);
1701 ResizeA(
m_eAlp, ne, nb, na + 1);
1702 ResizeA(
m_eAlp0, ne, nb, na + 1);
1703 ResizeA(
m_eAtt, ne, nb, na + 1);
1704 ResizeA(
m_eLor, ne, nb, na + 1);
1705 ResizeA(
m_iMob, ne, nb, na + 1);
1706 ResizeA(
m_iDis, ne, nb, na + 1);
1707 ResizeA(
m_iDifL, ne, nb, na + 1);
1708 ResizeA(
m_iDifT, ne, nb, na + 1);
1709 for (
auto& dif :
m_eDifM) ResizeA(dif, ne, nb, na + 1);
1710 for (
auto& exc :
m_excRates) ResizeA(exc, ne, nb, na + 1);
1711 for (
auto& ion :
m_ionRates) ResizeA(ion, ne, nb, na + 1);
1712 for (
int j = 0; j < nb; ++j) {
1713 for (
int i = 0; i < ne; ++i) {
1714 for (
int k = na; k > ia; k--) {
1728 for (
auto& dif :
m_eDifM) dif[k][j][i] = dif[k - 1][j][i];
1729 for (
auto& exc :
m_excRates) exc[k][j][i] = exc[k - 1][j][i];
1730 for (
auto& ion :
m_ionRates) ion[k][j][i] = ion[k - 1][j][i];
1737 for (
int k = 0; k < na; ++k) {
1738 for (
int j = 0; j < nb; ++j) {
1745 for (
int k = 0; k < na; ++k) {
1746 for (
int i = 0; i < ne; ++i) {
1753 for (
int j = 0; j < nb; ++j) {
1754 for (
int i = 0; i < ne; ++i) {
1767 constexpr int nMagboltzGases = 60;
1768 std::vector<double> mixture(nMagboltzGases, 0.);
1773 <<
" Error retrieving gas number for " <<
m_gas[i] <<
".\n";
1781 <<
" Writing gas tables to file " << filename <<
"\n";
1784 std::ofstream outfile;
1785 outfile.open(filename.c_str(), std::ios::out);
1786 if (!outfile.is_open()) {
1788 <<
" Cannot open file " << filename <<
".\n";
1794 std::bitset<20> gasok;
1796 std::string okstr(20,
'F');
1797 for (
unsigned int i = 0; i < 20; ++i) {
1798 if (gasok[i]) okstr[i] =
'T';
1800 if (
m_debug) std::cout <<
" GASOK bits: " << okstr <<
"\n";
1802 time_t rawtime = time(0);
1803 tm timeinfo = *localtime(&rawtime);
1804 char datebuf[80] = {0};
1805 char timebuf[80] = {0};
1807 strftime(datebuf,
sizeof(datebuf) - 1,
"%d/%m/%y", &timeinfo);
1808 strftime(timebuf,
sizeof(timebuf) - 1,
"%H.%M.%S", &timeinfo);
1810 std::string member =
"< none >";
1812 outfile <<
"*----.----1----.----2----.----3----.----4----.----"
1813 <<
"5----.----6----.----7----.----8----.----9----.---"
1814 <<
"10----.---11----.---12----.---13--\n";
1815 outfile <<
"% Created " << datebuf <<
" at " << timebuf <<
" ";
1816 outfile << member <<
" GAS ";
1819 outfile <<
"\"none" << std::string(25,
' ') <<
"\"\n";
1820 const int version = 12;
1821 outfile <<
" Version : " << version <<
"\n";
1822 outfile <<
" GASOK bits: " << okstr <<
"\n";
1823 std::stringstream ids;
1830 outfile <<
" Identifier: " << std::setw(80) << std::left << ids.str() <<
"\n";
1831 outfile <<
" Clusters : " << std::string(80,
' ') <<
"\n";
1832 outfile <<
" Dimension : ";
1839 const unsigned int nE =
m_eFields.size();
1840 const unsigned int nB =
m_bFields.size();
1841 const unsigned int nA =
m_bAngles.size();
1844 <<
"Dataset has the following dimensions:\n "
1845 <<
"3D = " <<
m_tab2d <<
" nE = " << nE <<
", nB = " << nB
1846 <<
", nA = " << nA <<
", nExc = "
1849 outfile << FmtInt(nE, 9) <<
" " << FmtInt(nA, 9) <<
" "
1850 << FmtInt(nB, 9) <<
" " << FmtInt(
m_excLevels.size(), 9) <<
" "
1853 outfile <<
" E fields \n";
1854 std::vector<double> efields =
m_eFields;
1858 PrintArray(efields, outfile, cnt, 5);
1859 if (nE % 5 != 0) outfile <<
"\n";
1861 outfile <<
" E-B angles \n";
1864 if (nA % 5 != 0) outfile <<
"\n";
1866 outfile <<
" B fields \n";
1867 std::vector<double> bfields =
m_bFields;
1868 for (
auto& field : bfields) field *= 100.;
1870 PrintArray(bfields, outfile, cnt, 5);
1871 if (nB % 5 != 0) outfile <<
"\n";
1874 outfile <<
" Mixture: \n";
1876 PrintArray(mixture, outfile, cnt, 5);
1877 if (nMagboltzGases % 5 != 0) outfile <<
"\n";
1882 outfile <<
" Excitation " << FmtInt(cnt, 5) <<
": " << std::setw(45);
1884 if (exc.label.find(
" ") != std::string::npos) {
1885 outfile <<
"\"" + exc.label +
"\"";
1887 outfile << exc.label;
1889 outfile <<
" " << FmtFloat(exc.energy) << FmtFloat(exc.prob)
1890 << FmtFloat(exc.rms) << FmtFloat(exc.dt) <<
"\n";
1895 outfile <<
" Ionisation " << FmtInt(cnt, 5) <<
": " << std::setw(45);
1897 if (ion.label.find(
" ") != std::string::npos) {
1898 outfile <<
"\"" + ion.label <<
"\"";
1900 outfile << ion.label;
1902 outfile <<
" " << FmtFloat(ion.energy) <<
"\n";
1907 outfile <<
" The gas tables follow:\n";
1909 for (
unsigned int i = 0; i < nE; ++i) {
1910 for (
unsigned int j = 0; j < nA; ++j) {
1911 for (
unsigned int k = 0; k < nB; ++k) {
1921 std::vector<double> val;
1926 val = {ve, 0., vb, 0., vx, 0.};
1932 double alpha =
m_eAlp.empty() ? -30. :
m_eAlp[j][k][i] - logp;
1933 double alpha0 =
m_eAlp0.empty() ? -30. :
m_eAlp0[j][k][i] - logp;
1934 double eta =
m_eAtt.empty() ? -30. :
m_eAtt[j][k][i] - logp;
1937 val.insert(val.end(), {dl, dt, alpha, alpha0, eta});
1939 val.insert(val.end(), {dl, 0., dt, 0., alpha, 0., alpha0, eta, 0.});
1942 double mu =
m_iMob.empty() ? 0. : 1.e3 *
m_iMob[j][k][i];
1946 double diss =
m_iDis.empty() ? -30. :
m_iDis[j][k][i] - logp;
1949 val.insert(val.end(), {mu, lor, diss});
1951 val.insert(val.end(), {mu, 0., lor, 0., diss, 0.});
1954 for (
int l = 0; l < 6; ++l) {
1961 if (!
m_tab2d) val.push_back(0.);
1965 if (rexc[j][k][i] > Small) {
1966 val.push_back(rexc[j][k][i]);
1970 if (!
m_tab2d) val.push_back(0.);
1973 if (rion[j][k][i] > Small) {
1974 val.push_back(rion[j][k][i]);
1978 if (!
m_tab2d) val.push_back(0.);
1980 PrintArray(val, outfile, cnt, 8);
1982 if (cnt % 8 != 0) outfile <<
"\n";
1989 int extrapH[13], extrapL[13];
1990 extrapL[0] = extrapL[1] = extrapL[2] =
m_extrVel.first;
1991 extrapH[0] = extrapH[1] = extrapH[2] =
m_extrVel.second;
1992 extrapL[3] = extrapL[8] = extrapL[10] =
m_extrDif.first;
1993 extrapH[3] = extrapH[8] = extrapH[10] =
m_extrDif.second;
2009 outfile <<
" H Extr: ";
2010 for (
int i = 0; i < 13; i++) outfile << FmtInt(extrapH[i], 5);
2012 outfile <<
" L Extr: ";
2013 for (
int i = 0; i < 13; i++) outfile << FmtInt(extrapL[i], 5);
2017 outfile <<
" Thresholds: " << FmtInt(
m_eThrAlp + 1, 10)
2021 interp[0] = interp[1] = interp[2] =
m_intpVel;
2022 interp[3] = interp[8] = interp[10] =
m_intpDif;
2030 outfile <<
" Interp: ";
2031 for (
int i = 0; i < 13; i++) outfile << FmtInt(interp[i], 5);
2033 outfile <<
" A =" << FmtFloat(0.) <<
", Z =" << FmtFloat(0.) <<
","
2034 <<
" EMPROB=" << FmtFloat(0.) <<
", EPAIR =" << FmtFloat(0.) <<
"\n";
2037 outfile <<
" Ion diffusion: " << FmtFloat(dli) << FmtFloat(dti) <<
"\n";
2038 outfile <<
" CMEAN =" << FmtFloat(0.) <<
", RHO =" << FmtFloat(0.) <<
","
2041 outfile <<
" CLSTYP : NOT SET \n"
2042 <<
" FCNCLS : " << std::string(80,
' ') <<
"\n"
2043 <<
" NCLS : " << FmtInt(0, 10) <<
"\n"
2044 <<
" Average : " << FmtFloat(0., 25, 18) <<
"\n"
2045 <<
" Heed initialisation done: F\n"
2046 <<
" SRIM initialisation done: F\n";
2055 if (!
m_eVelE.empty()) gasok.set(0);
2056 if (!
m_iMob.empty()) gasok.set(1);
2057 if (!
m_eDifL.empty()) gasok.set(2);
2058 if (!
m_eAlp.empty()) gasok.set(3);
2060 if (!
m_eAtt.empty()) gasok.set(5);
2061 if (!
m_eLor.empty()) gasok.set(6);
2062 if (!
m_eDifT.empty()) gasok.set(7);
2063 if (!
m_eVelB.empty()) gasok.set(8);
2064 if (!
m_eVelX.empty()) gasok.set(9);
2065 if (!
m_eDifM.empty()) gasok.set(10);
2066 if (!
m_iDis.empty()) gasok.set(11);
2075 <<
" Gas composition: " <<
m_name;
2084 std::cout <<
" Pressure: " <<
m_pressure <<
" Torr\n"
2090 std::cout <<
" Electric field range: " <<
m_eFields[0] <<
" - "
2094 std::cout <<
" Electric field: " <<
m_eFields[0] <<
" V/cm\n";
2096 std::cout <<
" Electric field range: not set\n";
2099 std::cout <<
" Magnetic field range: " <<
m_bFields[0] <<
" - "
2103 std::cout <<
" Magnetic field: " <<
m_bFields[0] <<
" T\n";
2105 std::cout <<
" Magnetic field range: not set\n";
2108 std::cout <<
" Angular range: " <<
m_bAngles[0] <<
" - "
2112 std::cout <<
" Angle between E and B: " <<
m_bAngles[0] <<
" rad\n";
2114 std::cout <<
" Angular range: not set\n";
2117 std::cout <<
" Available electron transport data:\n";
2119 std::cout <<
" Velocity along E\n";
2122 std::cout <<
" Velocity along Bt\n";
2125 std::cout <<
" Velocity along ExB\n";
2130 std::cout <<
" Interpolation order: " <<
m_intpVel <<
"\n";
2133 std::cout <<
" Longitudinal diffusion coefficient\n";
2136 std::cout <<
" Transverse diffusion coefficient\n";
2139 std::cout <<
" Diffusion tensor\n";
2143 std::cout <<
" Interpolation order: " <<
m_intpDif <<
"\n";
2146 std::cout <<
" Townsend coefficient\n";
2148 std::cout <<
" Interpolation order: " <<
m_intpAlp <<
"\n";
2151 std::cout <<
" Attachment coefficient\n";
2153 std::cout <<
" Interpolation order: " <<
m_intpAtt <<
"\n";
2156 std::cout <<
" Lorentz Angle\n";
2158 std::cout <<
" Interpolation order: " <<
m_intpLor <<
"\n";
2161 std::cout <<
" Excitation rates\n";
2163 std::cout <<
" " << exc.label <<
"\n";
2164 std::cout <<
" Energy = " << exc.energy <<
" eV";
2165 if (exc.prob > 0.) {
2166 std::cout <<
", Penning transfer probability = " << exc.prob;
2171 std::cout <<
" Interpolation order: " <<
m_intpExc <<
"\n";
2174 std::cout <<
" Ionisation rates\n";
2176 std::cout <<
" " << ion.label <<
"\n";
2177 std::cout <<
" Threshold = " << ion.energy <<
" eV\n";
2180 std::cout <<
" Interpolation order: " <<
m_intpIon <<
"\n";
2186 std::cout <<
" none\n";
2189 std::cout <<
" Available ion transport data:\n";
2191 std::cout <<
" Mobility\n";
2193 std::cout <<
" Interpolation order: " <<
m_intpMob <<
"\n";
2196 std::cout <<
" Longitudinal diffusion coefficient\n";
2199 std::cout <<
" Transverse diffusion coefficient\n";
2203 std::cout <<
" Interpolation order: " <<
m_intpDif <<
"\n";
2206 std::cout <<
" Dissociation coefficient\n";
2208 std::cout <<
" Interpolation order: " <<
m_intpDis <<
"\n";
2211 std::cout <<
" none\n";
2217 std::ifstream infile;
2218 infile.open(filename.c_str(), std::ios::in);
2221 std::cerr <<
m_className <<
"::LoadIonMobility:\n"
2222 <<
" Error opening file " << filename <<
".\n";
2226 std::vector<std::pair<double, double> > data;
2229 constexpr size_t size = 100;
2231 while (infile.getline(line, size)) {
2233 char* token = strtok(line,
" ,\t");
2235 if (strcmp(token,
"#") == 0 || strcmp(token,
"*") == 0 ||
2236 strcmp(token,
"//") == 0) {
2239 double field = atof(token);
2240 token = strtok(NULL,
" ,\t");
2242 std::cerr <<
m_className <<
"::LoadIonMobility:\n"
2243 <<
" Found E/N but no mobility before the end-of-line.\n"
2244 <<
" Skipping line " << i <<
".\n";
2247 double mu = atof(token);
2249 std::cout <<
" E/N = " << field <<
" Td: mu = " << mu <<
" cm2/(Vs)\n";
2254 std::cerr <<
m_className <<
"::LoadIonMobility:\n"
2255 <<
" Negative electric field (line " << i <<
").\n";
2259 data.push_back(std::make_pair(field, mu));
2264 std::cerr <<
m_className <<
"::LoadIonMobilities:\n"
2265 <<
" No valid data found.\n";
2269 std::sort(data.begin(), data.end());
2274 const double scaleMobility = 1.e-9 * (AtmosphericPressure /
m_pressure) *
2277 const size_t ne = data.size();
2278 std::vector<double> efields(ne, 0.);
2279 std::vector<double> mobilities(ne, 0.);
2280 for (
size_t j = 0; j < ne; ++j) {
2282 efields[j] = data[j].first * scaleField;
2283 mobilities[j] = data[j].second * scaleMobility;
2286 std::cout <<
m_className <<
"::LoadIonMobility:\n"
2287 <<
" Read " << ne <<
" values from file " << filename <<
"\n";
2303 const double lambda) {
2305 if (r < 0. || r > 1.) {
2306 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2307 <<
" Transfer probability must be in the range [0, 1].\n";
2314 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2315 <<
" Global Penning transfer parameters set to:\n"
2321 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n Warning: present"
2322 <<
" gas table has no ionisation rates.\n Ignore this message "
2323 <<
"if you are using microscopic tracking only.\n";
2326 double minIonPot = -1.;
2328 if (minIonPot < 0.) {
2329 minIonPot = ion.energy;
2331 minIonPot = std::min(minIonPot, ion.energy);
2336 unsigned int nLevelsFound = 0;
2338 if (exc.energy < minIonPot)
continue;
2343 if (nLevelsFound > 0) {
2344 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2345 <<
" Updated transfer probabilities for " << nLevelsFound
2346 <<
" excitation rates.\n";
2349 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n Warning: present"
2350 <<
" gas table has no eligible excitation rates.\n Ignore this"
2351 <<
" message if you are using microscopic tracking only.\n";
2357 std::string gasname) {
2359 if (r < 0. || r > 1.) {
2360 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2361 <<
" Transfer probability must be in the range [0, 1].\n";
2367 if (gasname.empty()) {
2368 std::cerr <<
m_className <<
"::EnablePenningTransfer: Unknown gas name.\n";
2375 if (
m_gas[i] == gasname) {
2384 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n"
2385 <<
" Requested gas (" << gasname
2386 <<
") is not part of the present gas mixture.\n";
2392 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n Warning: present"
2393 <<
" gas table has no ionisation rates.\n Ignore this message"
2394 <<
" if you are using microscopic tracking only.\n";
2397 double minIonPot = -1.;
2399 if (minIonPot < 0.) {
2400 minIonPot = ion.energy;
2402 minIonPot = std::min(minIonPot, ion.energy);
2406 unsigned int nLevelsFound = 0;
2408 if (exc.energy < minIonPot)
continue;
2411 const auto pos = exc.label.find(
'-');
2412 if (pos == std::string::npos)
continue;
2413 if (
GetGasName(exc.label.substr(0, pos)) != gasname)
continue;
2418 if (nLevelsFound > 0) {
2419 std::cout <<
m_className <<
"::EnablePenningTransfer:\n"
2420 <<
" Updated transfer probabilities for " << nLevelsFound
2421 <<
" excitation rates.\n";
2424 std::cerr <<
m_className <<
"::EnablePenningTransfer:\n Warning: present"
2425 <<
" gas table has no eligible excitation rates.\n Ignore this"
2426 <<
" message if you are using microscopic tracking only.\n";
2450 if (gasname.empty()) {
2451 std::cerr <<
m_className <<
"::DisablePenningTransfer: Unknown gas name.\n";
2458 if (
m_gas[i] == gasname) {
2467 std::cerr <<
m_className <<
"::DisablePenningTransfer:\n"
2468 <<
" Requested gas (" << gasname
2469 <<
") is not part of the present gas mixture.\n";
2476 const auto pos = exc.label.find(
'-');
2477 if (pos == std::string::npos)
continue;
2478 if (
GetGasName(exc.label.substr(0, pos)) != gasname)
continue;
2494 std::cerr <<
m_className <<
"::AdjustTownsendCoefficient:\n "
2495 <<
"Present gas table does not include Townsend coefficients.\n";
2500 std::cerr <<
m_className <<
"::AdjustTownsendCoefficient:\n "
2501 <<
"Present gas table does not include excitation rates.\n";
2505 std::cerr <<
m_className <<
"::AdjustTownsendCoefficient:\n "
2506 <<
"Present gas table does not include ionisation rates.\n";
2509 const unsigned int nE =
m_eFields.size();
2510 const unsigned int nB =
m_bFields.size();
2511 const unsigned int nA =
m_bAngles.size();
2513 std::cout <<
m_className <<
"::AdjustTownsendCoefficient:\n"
2514 <<
" Entry Exc. Ion.\n";
2516 for (
unsigned int i = 0; i < nE; ++i) {
2517 for (
unsigned int j = 0; j < nA; ++j) {
2518 for (
unsigned int k = 0; k < nB; ++k) {
2522 rion += ion[j][k][i];
2527 for (
unsigned int ie = 0; ie < nexc; ++ie) {
2531 std::cout << FmtInt(i, 4) << FmtInt(j, 4) << FmtInt(k, 4)
2532 << FmtFloat(rexc, 12, 5) << FmtFloat(rion, 12, 5) <<
"\n";
2535 double alpha0 =
m_eAlp0[j][k][i];
2536 if (alpha0 < -20.) {
2541 double alpha1 = alpha0;
2542 if (rion > 0.) alpha1 *= (rexc + rion) / rion;
2554 if (gasname ==
"CF4") {
2555 a = 12.0107 + 4 * 18.9984032;
2558 }
else if (gasname ==
"Ar") {
2561 }
else if (gasname ==
"He") {
2564 }
else if (gasname ==
"He-3") {
2567 }
else if (gasname ==
"Ne") {
2570 }
else if (gasname ==
"Kr") {
2573 }
else if (gasname ==
"Xe") {
2576 }
else if (gasname ==
"CH4") {
2577 a = 12.0107 + 4 * 1.00794;
2579 }
else if (gasname ==
"C2H6") {
2580 a = 2 * 12.0107 + 6 * 1.00794;
2582 }
else if (gasname ==
"C3H8") {
2583 a = 3 * 12.0107 + 8 * 1.00794;
2585 }
else if (gasname ==
"iC4H10") {
2586 a = 4 * 12.0107 + 10 * 1.00794;
2588 }
else if (gasname ==
"CO2") {
2589 a = 12.0107 + 2 * 15.9994;
2591 }
else if (gasname ==
"neoC5H12") {
2592 a = 5 * 12.0107 + 12 * 1.00794;
2594 }
else if (gasname ==
"H2O") {
2595 a = 2 * 1.00794 + 15.9994;
2597 }
else if (gasname ==
"O2") {
2600 }
else if (gasname ==
"N2") {
2603 }
else if (gasname ==
"NO") {
2604 a = 14.0067 + 15.9994;
2606 }
else if (gasname ==
"N2O") {
2607 a = 2 * 14.0067 + 15.9994;
2609 }
else if (gasname ==
"C2H4") {
2610 a = 2 * 12.0107 + 4 * 1.00794;
2612 }
else if (gasname ==
"C2H2") {
2613 a = 2 * 12.0107 + 2 * 1.00794;
2615 }
else if (gasname ==
"H2" || gasname ==
"paraH2") {
2618 }
else if (gasname ==
"D2" || gasname ==
"orthoD2") {
2619 a = 2 * 2.01410177785;
2621 }
else if (gasname ==
"CO") {
2622 a = 12.0107 + 15.9994;
2624 }
else if (gasname ==
"Methylal") {
2625 a = 3 * 12.0107 + 8 * 1.00794 + 2 * 15.9994;
2626 z = 3 * 6 + 8 + 2 * 8;
2627 }
else if (gasname ==
"DME") {
2628 a = 4 * 12.0107 + 10 * 1.00794 + 2 * 15.9994;
2629 z = 4 * 6 + 10 + 2 * 8;
2630 }
else if (gasname ==
"Reid-Step" || gasname ==
"Maxwell-Model" ||
2631 gasname ==
"Reid-Ramp") {
2634 }
else if (gasname ==
"C2F6") {
2635 a = 2 * 12.0107 + 6 * 18.9984032;
2637 }
else if (gasname ==
"SF6") {
2638 a = 32.065 + 6 * 18.9984032;
2640 }
else if (gasname ==
"NH3") {
2641 a = 14.0067 + 3 * 1.00794;
2643 }
else if (gasname ==
"C3H6") {
2644 a = 3 * 12.0107 + 6 * 1.00794;
2646 }
else if (gasname ==
"cC3H6") {
2647 a = 3 * 12.0107 + 6 * 1.00794;
2649 }
else if (gasname ==
"CH3OH") {
2650 a = 12.0107 + 4 * 1.00794 + 15.9994;
2652 }
else if (gasname ==
"C2H5OH") {
2653 a = 2 * 12.0107 + 6 * 1.00794 + 15.9994;
2655 }
else if (gasname ==
"C3H7OH" || gasname ==
"nC3H7OH") {
2656 a = 3 * 12.0107 + 8 * 1.00794 + 15.9994;
2658 }
else if (gasname ==
"Cs") {
2661 }
else if (gasname ==
"F2") {
2664 }
else if (gasname ==
"CS2") {
2665 a = 12.0107 + 2 * 32.065;
2667 }
else if (gasname ==
"COS") {
2668 a = 12.0107 + 15.9994 + 32.065;
2670 }
else if (gasname ==
"CD4") {
2671 a = 12.0107 + 4 * 2.01410177785;
2673 }
else if (gasname ==
"BF3") {
2674 a = 10.811 + 3 * 18.9984032;
2676 }
else if (gasname ==
"C2H2F4") {
2677 a = 2 * 12.0107 + 2 * 1.00794 + 4 * 18.9984032;
2678 z = 2 * 6 + 2 + 4 * 9;
2679 }
else if (gasname ==
"CHF3") {
2680 a = 12.0107 + 1.00794 + 3 * 18.9984032;
2682 }
else if (gasname ==
"CF3Br") {
2683 a = 12.0107 + 3 * 18.9984032 + 79.904;
2685 }
else if (gasname ==
"C3F8") {
2686 a = 3 * 12.0107 + 8 * 18.9984032;
2688 }
else if (gasname ==
"O3") {
2691 }
else if (gasname ==
"Hg") {
2694 }
else if (gasname ==
"H2S") {
2695 a = 2 * 1.00794 + 32.065;
2697 }
else if (gasname ==
"nC4H10") {
2698 a = 4 * 12.0107 + 10 * 1.00794;
2700 }
else if (gasname ==
"nC5H12") {
2701 a = 5 * 12.0107 + 12 * 1.00794;
2703 }
else if (gasname ==
"GeH4") {
2704 a = 72.64 + 4 * 1.00794;
2706 }
else if (gasname ==
"SiH4") {
2707 a = 28.0855 + 4 * 1.00794;
2720 switch (gasnumber) {
2774 return "Maxwell-Model";
2808 return version <= 11 ?
"He-3" :
"TMA";
2810 return version <= 11 ?
"He" :
"paraH2";
2812 return version <= 11 ?
"Ne" :
"nC3H7OH";
2816 return version <= 11 ?
"Kr" :
"orthoD2";
2849 std::transform(input.begin(), input.end(), input.begin(), toupper);
2851 if (input.empty())
return "";
2853 if (input ==
"CF4" || input ==
"FREON" || input ==
"FREON-14" ||
2854 input ==
"TETRAFLUOROMETHANE") {
2856 }
else if (input ==
"AR" || input ==
"ARGON") {
2858 }
else if (input ==
"HE" || input ==
"HELIUM" || input ==
"HE-4" ||
2859 input ==
"HE 4" || input ==
"HE4" || input ==
"4-HE" ||
2860 input ==
"4 HE" || input ==
"4HE" || input ==
"HELIUM-4" ||
2861 input ==
"HELIUM 4" || input ==
"HELIUM4") {
2863 }
else if (input ==
"HE-3" || input ==
"HE3" || input ==
"HELIUM-3" ||
2864 input ==
"HELIUM 3" || input ==
"HELIUM3") {
2866 }
else if (input ==
"NE" || input ==
"NEON") {
2868 }
else if (input ==
"KR" || input ==
"KRYPTON") {
2870 }
else if (input ==
"XE" || input ==
"XENON") {
2872 }
else if (input ==
"CH4" || input ==
"METHANE") {
2874 }
else if (input ==
"C2H6" || input ==
"ETHANE") {
2876 }
else if (input ==
"C3H8" || input ==
"PROPANE") {
2878 }
else if (input ==
"C4H10" || input ==
"ISOBUTANE" || input ==
"ISO" ||
2879 input ==
"IC4H10" || input ==
"ISO-C4H10" || input ==
"ISOC4H10") {
2881 }
else if (input ==
"CO2" || input ==
"CARBON-DIOXIDE" ||
2882 input ==
"CARBON DIOXIDE" || input ==
"CARBONDIOXIDE") {
2884 }
else if (input ==
"NEOPENTANE" || input ==
"NEO-PENTANE" ||
2885 input ==
"NEO-C5H12" || input ==
"NEOC5H12" ||
2886 input ==
"DIMETHYLPROPANE" || input ==
"C5H12") {
2888 }
else if (input ==
"H2O" || input ==
"WATER" || input ==
"WATER-VAPOUR" ||
2889 input ==
"WATER VAPOUR") {
2891 }
else if (input ==
"O2" || input ==
"OXYGEN") {
2893 }
else if (input ==
"NI" || input ==
"NITRO" || input ==
"N2" ||
2894 input ==
"NITROGEN") {
2896 }
else if (input ==
"NO" || input ==
"NITRIC-OXIDE" || input ==
"NITRIC OXIDE" ||
2897 input ==
"NITROGEN-MONOXIDE" || input ==
"NITROGEN MONOXIDE") {
2899 }
else if (input ==
"N2O" || input ==
"NITROUS-OXIDE" || input ==
"NITROUS OXIDE" ||
2900 input ==
"DINITROGEN-MONOXIDE" || input ==
"LAUGHING-GAS") {
2902 }
else if (input ==
"C2H4" || input ==
"ETHENE" || input ==
"ETHYLENE") {
2904 }
else if (input ==
"C2H2" || input ==
"ACETYL" || input ==
"ACETYLENE" ||
2905 input ==
"ETHYNE") {
2907 }
else if (input ==
"H2" || input ==
"HYDROGEN") {
2909 }
else if (input ==
"PARA H2" || input ==
"PARA-H2" ||
2910 input ==
"PARAH2" || input ==
"PARA HYDROGEN" ||
2911 input ==
"PARA-HYDROGEN" || input ==
"PARAHYDROGEN") {
2913 }
else if (input ==
"D2" || input ==
"DEUTERIUM") {
2915 }
else if (input ==
"ORTHO D2" || input ==
"ORTHO-D2" ||
2916 input ==
"ORTHOD2" || input ==
"ORTHO DEUTERIUM" ||
2917 input ==
"ORTHO-DEUTERIUM" || input ==
"ORTHODEUTERIUM") {
2919 }
else if (input ==
"CO" || input ==
"CARBON-MONOXIDE" ||
2920 input ==
"CARBON MONOXIDE") {
2922 }
else if (input ==
"METHYLAL" || input ==
"METHYLAL-HOT" || input ==
"DMM" ||
2923 input ==
"DIMETHOXYMETHANE" || input ==
"FORMAL" || input ==
"C3H8O2") {
2926 }
else if (input ==
"DME" || input ==
"DIMETHYL-ETHER" || input ==
"DIMETHYLETHER" ||
2927 input ==
"DIMETHYL ETHER" || input ==
"METHYL ETHER" ||
2928 input ==
"METHYL-ETHER" || input ==
"METHYLETHER" ||
2929 input ==
"WOOD-ETHER" || input ==
"WOODETHER" || input ==
"WOOD ETHER" ||
2930 input ==
"DIMETHYL OXIDE" || input ==
"DIMETHYL-OXIDE" ||
2931 input ==
"DEMEON" || input ==
"METHOXYMETHANE" || input ==
"C4H10O2") {
2933 }
else if (input ==
"REID-STEP") {
2935 }
else if (input ==
"MAXWELL-MODEL") {
2936 return "Maxwell-Model";
2937 }
else if (input ==
"REID-RAMP") {
2939 }
else if (input ==
"C2F6" || input ==
"FREON-116" || input ==
"ZYRON-116" ||
2940 input ==
"ZYRON-116-N5" || input ==
"HEXAFLUOROETHANE") {
2942 }
else if (input ==
"SF6" || input ==
"SULPHUR-HEXAFLUORIDE" ||
2943 input ==
"SULFUR-HEXAFLUORIDE" || input ==
"SULPHUR HEXAFLUORIDE" ||
2944 input ==
"SULFUR HEXAFLUORIDE") {
2946 }
else if (input ==
"NH3" || input ==
"AMMONIA") {
2948 }
else if (input ==
"C3H6" || input ==
"PROPENE" || input ==
"PROPYLENE") {
2950 }
else if (input ==
"C-PROPANE" || input ==
"CYCLO-PROPANE" ||
2951 input ==
"CYCLO PROPANE" || input ==
"CYCLOPROPANE" ||
2952 input ==
"C-C3H6" || input ==
"CC3H6" || input ==
"CYCLO-C3H6") {
2954 }
else if (input ==
"METHANOL" || input ==
"METHYL-ALCOHOL" ||
2955 input ==
"METHYL ALCOHOL" || input ==
"WOOD ALCOHOL" ||
2956 input ==
"WOOD-ALCOHOL" || input ==
"CH3OH") {
2958 }
else if (input ==
"ETHANOL" || input ==
"ETHYL-ALCOHOL" ||
2959 input ==
"ETHYL ALCOHOL" || input ==
"GRAIN ALCOHOL" ||
2960 input ==
"GRAIN-ALCOHOL" || input ==
"C2H5OH") {
2962 }
else if (input ==
"PROPANOL" || input ==
"2-PROPANOL" || input ==
"ISOPROPYL" ||
2963 input ==
"ISO-PROPANOL" || input ==
"ISOPROPANOL" ||
2964 input ==
"ISOPROPYL ALCOHOL" || input ==
"ISOPROPYL-ALCOHOL" ||
2965 input ==
"C3H7OH") {
2967 }
else if (input ==
"NPROPANOL" || input ==
"N-PROPANOL" ||
2968 input ==
"1-PROPANOL" || input ==
"PROPYL ALCOHOL" ||
2969 input ==
"PROPYL-ALCOHOL" || input ==
"N-PROPYL ALCOHOL" ||
2970 input ==
"NC3H7OH" || input ==
"N-C3H7OH") {
2972 }
else if (input ==
"CS" || input ==
"CESIUM" || input ==
"CAESIUM") {
2974 }
else if (input ==
"F2" || input ==
"FLUOR" || input ==
"FLUORINE") {
2976 }
else if (input ==
"CS2" || input ==
"CARBON-DISULPHIDE" ||
2977 input ==
"CARBON-DISULFIDE" || input ==
"CARBON DISULPHIDE" ||
2978 input ==
"CARBON DISULFIDE") {
2980 }
else if (input ==
"COS" || input ==
"CARBONYL-SULPHIDE" ||
2981 input ==
"CARBONYL-SULFIDE" || input ==
"CARBONYL SULFIDE") {
2983 }
else if (input ==
"DEUT-METHANE" || input ==
"DEUTERIUM-METHANE" ||
2984 input ==
"DEUTERATED-METHANE" || input ==
"DEUTERATED METHANE" ||
2985 input ==
"DEUTERIUM METHANE" || input ==
"CD4") {
2987 }
else if (input ==
"BF3" || input ==
"BORON-TRIFLUORIDE" ||
2988 input ==
"BORON TRIFLUORIDE") {
2990 }
else if (input ==
"C2HF5" || input ==
"C2H2F4" || input ==
"C2F5H" ||
2991 input ==
"C2F4H2" || input ==
"FREON 134" || input ==
"FREON 134A" ||
2992 input ==
"FREON-134" || input ==
"FREON-134-A" || input ==
"FREON 125" ||
2993 input ==
"ZYRON 125" || input ==
"FREON-125" || input ==
"ZYRON-125" ||
2994 input ==
"TETRAFLUOROETHANE" || input ==
"PENTAFLUOROETHANE") {
2997 }
else if (input ==
"TMA" || input ==
"TRIMETHYLAMINE" || input ==
"N(CH3)3" ||
2998 input ==
"N-(CH3)3") {
3000 }
else if (input ==
"CHF3" || input ==
"FREON-23" || input ==
"TRIFLUOROMETHANE" ||
3001 input ==
"FLUOROFORM") {
3003 }
else if (input ==
"CF3BR" || input ==
"TRIFLUOROBROMOMETHANE" ||
3004 input ==
"BROMOTRIFLUOROMETHANE" || input ==
"HALON-1301" ||
3005 input ==
"HALON 1301" || input ==
"FREON-13B1" || input ==
"FREON 13BI") {
3007 }
else if (input ==
"C3F8" || input ==
"OCTAFLUOROPROPANE" || input ==
"R218" ||
3008 input ==
"R-218" || input ==
"FREON 218" || input ==
"FREON-218" ||
3009 input ==
"PERFLUOROPROPANE" || input ==
"RC 218" || input ==
"PFC 218" ||
3010 input ==
"RC-218" || input ==
"PFC-218" || input ==
"FLUTEC PP30" ||
3011 input ==
"GENETRON 218") {
3013 }
else if (input ==
"OZONE" || input ==
"O3") {
3015 }
else if (input ==
"MERCURY" || input ==
"HG" || input ==
"HG2") {
3017 }
else if (input ==
"H2S" || input ==
"HYDROGEN SULPHIDE" || input ==
"SEWER GAS" ||
3018 input ==
"HYDROGEN-SULPHIDE" || input ==
"SEWER-GAS" ||
3019 input ==
"HYDROGEN SULFIDE" || input ==
"HEPATIC ACID" ||
3020 input ==
"HYDROGEN-SULFIDE" || input ==
"HEPATIC-ACID" ||
3021 input ==
"SULFUR HYDRIDE" || input ==
"DIHYDROGEN MONOSULFIDE" ||
3022 input ==
"SULFUR-HYDRIDE" || input ==
"DIHYDROGEN-MONOSULFIDE" ||
3023 input ==
"DIHYDROGEN MONOSULPHIDE" || input ==
"SULPHUR HYDRIDE" ||
3024 input ==
"DIHYDROGEN-MONOSULPHIDE" || input ==
"SULPHUR-HYDRIDE" ||
3025 input ==
"STINK DAMP" || input ==
"SULFURATED HYDROGEN" ||
3026 input ==
"STINK-DAMP" || input ==
"SULFURATED-HYDROGEN") {
3028 }
else if (input ==
"N-BUTANE" || input ==
"N-C4H10" || input ==
"NBUTANE" ||
3029 input ==
"NC4H10") {
3031 }
else if (input ==
"N-PENTANE" || input ==
"N-C5H12" || input ==
"NPENTANE" ||
3032 input ==
"NC5H12") {
3034 }
else if (input ==
"NI-PHELPS" || input ==
"NI PHELPS" ||
3035 input ==
"NITROGEN-PHELPS" || input ==
"NITROGEN PHELPHS" ||
3036 input ==
"N2-PHELPS" || input ==
"N2 PHELPS" || input ==
"N2 (PHELPS)") {
3038 return "N2 (Phelps)";
3039 }
else if (input ==
"GERMANE" || input ==
"GERM" || input ==
"GERMANIUM-HYDRIDE" ||
3040 input ==
"GERMANIUM HYDRIDE" || input ==
"GERMANIUM TETRAHYDRIDE" ||
3041 input ==
"GERMANIUM-TETRAHYDRIDE" || input ==
"GERMANOMETHANE" ||
3042 input ==
"MONOGERMANE" || input ==
"GEH4") {
3044 }
else if (input ==
"SILANE" || input ==
"SIL" || input ==
"SILICON-HYDRIDE" ||
3045 input ==
"SILICON HYDRIDE" || input ==
"SILICON-TETRAHYDRIDE" ||
3046 input ==
"SILICANE" || input ==
"MONOSILANE" || input ==
"SIH4") {
3051 <<
" Gas " << input <<
" is not recognized.\n";
3057 if (input.empty())
return 0;
3059 if (input ==
"CF4") {
3061 }
else if (input ==
"Ar") {
3063 }
else if (input ==
"He" || input ==
"He-4") {
3065 }
else if (input ==
"He-3") {
3067 }
else if (input ==
"Ne") {
3069 }
else if (input ==
"Kr") {
3071 }
else if (input ==
"Xe") {
3073 }
else if (input ==
"CH4") {
3076 }
else if (input ==
"C2H6") {
3079 }
else if (input ==
"C3H8") {
3082 }
else if (input ==
"iC4H10") {
3085 }
else if (input ==
"CO2") {
3087 }
else if (input ==
"neoC5H12") {
3090 }
else if (input ==
"H2O") {
3092 }
else if (input ==
"O2") {
3094 }
else if (input ==
"N2") {
3096 }
else if (input ==
"NO") {
3099 }
else if (input ==
"N2O") {
3102 }
else if (input ==
"C2H4") {
3105 }
else if (input ==
"C2H2") {
3108 }
else if (input ==
"H2") {
3110 }
else if (input ==
"D2") {
3113 }
else if (input ==
"CO") {
3115 }
else if (input ==
"Methylal") {
3118 }
else if (input ==
"DME") {
3120 }
else if (input ==
"Reid-Step") {
3122 }
else if (input ==
"Maxwell-Model") {
3124 }
else if (input ==
"Reid-Ramp") {
3126 }
else if (input ==
"C2F6") {
3128 }
else if (input ==
"SF6") {
3130 }
else if (input ==
"NH3") {
3132 }
else if (input ==
"C3H6") {
3135 }
else if (input ==
"cC3H6") {
3138 }
else if (input ==
"CH3OH") {
3141 }
else if (input ==
"C2H5OH") {
3144 }
else if (input ==
"C3H7OH") {
3147 }
else if (input ==
"Cs") {
3149 }
else if (input ==
"F2") {
3152 }
else if (input ==
"CS2") {
3154 }
else if (input ==
"COS") {
3156 }
else if (input ==
"CD4") {
3159 }
else if (input ==
"BF3") {
3161 }
else if (input ==
"C2HF5" || input ==
"C2H2F4") {
3163 }
else if (input ==
"TMA") {
3165 }
else if (input ==
"paraH2") {
3167 }
else if (input ==
"nC3H7OH") {
3169 }
else if (input ==
"orthoD2") {
3171 }
else if (input ==
"CHF3") {
3173 }
else if (input ==
"CF3Br") {
3175 }
else if (input ==
"C3F8") {
3177 }
else if (input ==
"O3") {
3180 }
else if (input ==
"Hg") {
3182 }
else if (input ==
"H2S") {
3184 }
else if (input ==
"nC4H10") {
3187 }
else if (input ==
"nC5H12") {
3190 }
else if (input ==
"N2 (Phelps)") {
3192 }
else if (input ==
"GeH4") {
3195 }
else if (input ==
"SiH4") {
3200 std::cerr <<
m_className <<
"::GetGasNumberGasFile:\n"
3201 <<
" Gas " << input <<
" not found.\n";
3206 const unsigned int i) {
3209 <<
"::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
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
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
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)