Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
MediumMagboltz.cc
Go to the documentation of this file.
1#include <iostream>
2#include <iomanip>
3#include <fstream>
4#include <cmath>
5
6#include <map>
7
8#include <TMath.h>
9
10#include "MediumMagboltz.hh"
11#include "MagboltzInterface.hh"
12#include "Random.hh"
14#include "GarfieldConstants.hh"
15#include "OpticalData.hh"
16
17namespace Garfield {
18
19const int MediumMagboltz::DxcTypeRad = 0;
20const int MediumMagboltz::DxcTypeCollIon = 1;
21const int MediumMagboltz::DxcTypeCollNonIon = -1;
22
24 : MediumGas(),
25 eFinal(40.),
26 eStep(eFinal / nEnergySteps),
27 eHigh(1.e4),
28 eHighLog(log(eHigh)),
29 lnStep(1.),
30 useAutoAdjust(true),
31 useCsOutput(false),
32 nTerms(0),
33 useAnisotropic(true),
34 nPenning(0),
35 useDeexcitation(false),
36 useRadTrap(true),
37 nDeexcitations(0),
38 nIonisationProducts(0),
39 nDeexcitationProducts(0),
40 useOpalBeaty(true),
41 useGreenSawada(false),
42 eFinalGamma(20.),
43 eStepGamma(eFinalGamma / nEnergyStepsGamma) {
44
45 fit3d4p = fitHigh4p = 1.;
49 fit4sEtaC2H6 = 0.5;
50 fitLineCut = 1000;
51
52 m_className = "MediumMagboltz";
53
54 // Set physical constants in Magboltz common blocks.
55 Magboltz::cnsts_.echarg = ElementaryCharge * 1.e-15;
56 Magboltz::cnsts_.emass = ElectronMassGramme;
57 Magboltz::cnsts_.amu = AtomicMassUnit;
58 Magboltz::cnsts_.pir2 = BohrRadius * BohrRadius * Pi;
59 Magboltz::inpt_.ary = RydbergEnergy;
60
61 // Set parameters in Magboltz common blocks.
63 Magboltz::inpt_.nStep = nEnergySteps;
64 // Select the scattering model.
65 Magboltz::inpt_.nAniso = 2;
66 // Max. energy [eV]
67 Magboltz::inpt_.efinal = eFinal;
68 // Energy step size [eV]
69 Magboltz::inpt_.estep = eStep;
70 // Temperature and pressure
71 Magboltz::inpt_.akt = BoltzmannConstant * m_temperature;
72 Magboltz::inpt_.tempc = m_temperature - ZeroCelsius;
74 // Disable Penning transfer.
75 Magboltz::inpt_.ipen = 0;
76
77 // Initialise Penning parameters
78 for (int i = nMaxLevels; i--;) {
79 rPenning[i] = 0.;
80 lambdaPenning[i] = 0.;
81 }
82
83 m_isChanged = true;
84
87 m_microscopic = true;
88
89 // Initialize the collision counters.
90 nCollisionsDetailed.clear();
91 for (int i = nCsTypes; i--;) nCollisions[i] = 0;
92 for (int i = nCsTypesGamma; i--;) nPhotonCollisions[i] = 0;
93
94 ionProducts.clear();
95 dxcProducts.clear();
96
97 for (unsigned int i = 0; i < m_nMaxGases; ++i) scaleExc[i] = 1.;
98}
99
101
102 if (e <= Small) {
103 std::cerr << m_className << "::SetMaxElectronEnergy:\n";
104 std::cerr << " Provided upper electron energy limit (" << e
105 << " eV) is too small.\n";
106 return false;
107 }
108 eFinal = e;
109
110 // Determine the energy interval size.
111 if (eFinal <= eHigh) {
112 eStep = eFinal / nEnergySteps;
113 } else {
114 eStep = eHigh / nEnergySteps;
115 }
116
117 // Set max. energy and step size also in Magboltz common block.
118 Magboltz::inpt_.efinal = eFinal;
119 Magboltz::inpt_.estep = eStep;
120
121 // Force recalculation of the scattering rates table.
122 m_isChanged = true;
123
124 return true;
125}
126
128
129 if (e <= Small) {
130 std::cerr << m_className << "::SetMaxPhotonEnergy:\n";
131 std::cerr << " Provided upper photon energy limit (" << e
132 << " eV) is too small.\n";
133 return false;
134 }
135 eFinalGamma = e;
136
137 // Determine the energy interval size.
138 eStepGamma = eFinalGamma / nEnergyStepsGamma;
139
140 // Force recalculation of the scattering rates table.
141 m_isChanged = true;
142
143 return true;
144}
145
147
148 useOpalBeaty = true;
149 useGreenSawada = false;
150}
151
153
154 useOpalBeaty = false;
155 useGreenSawada = true;
156 if (m_isChanged) return;
157
158 bool allset = true;
159 for (unsigned int i = 0; i < m_nComponents; ++i) {
160 if (!m_hasGreenSawada[i]) {
161 if (allset) {
162 std::cout << m_className << "::SetSplittingFunctionGreenSawada:\n";
163 allset = false;
164 }
165 std::cout << " Fit parameters for " << gas[i] << " not available.\n";
166 std::cout << " Opal-Beaty formula is used instead.\n";
167 }
168 }
169}
170
172
173 useOpalBeaty = false;
174 useGreenSawada = false;
175}
176
178
179 if (usePenning) {
180 std::cout << m_className << "::EnableDeexcitation:\n";
181 std::cout << " Penning transfer will be switched off.\n";
182 }
183 // if (useRadTrap) {
184 // std::cout << " Radiation trapping is switched on.\n";
185 // } else {
186 // std::cout << " Radiation trapping is switched off.\n";
187 // }
188 usePenning = false;
189 useDeexcitation = true;
190 m_isChanged = true;
191 nDeexcitationProducts = 0;
192}
193
195
196 useRadTrap = true;
197 if (!useDeexcitation) {
198 std::cout << m_className << "::EnableRadiationTrapping:\n";
199 std::cout << " Radiation trapping is enabled"
200 << " but de-excitation is not.\n";
201 } else {
202 m_isChanged = true;
203 }
204}
205
207 const double lambda) {
208
209 if (r < 0. || r > 1.) {
210 std::cerr << m_className << "::EnablePenningTransfer:\n";
211 std::cerr << " Penning transfer probability must be "
212 << " in the range [0, 1].\n";
213 return;
214 }
215
216 rPenningGlobal = r;
217 if (lambda < Small) {
219 } else {
220 lambdaPenningGlobal = lambda;
221 }
222
223 std::cout << m_className << "::EnablePenningTransfer:\n";
224 std::cout << " Global Penning transfer parameters set to: \n";
225 std::cout << " r = " << rPenningGlobal << "\n";
226 std::cout << " lambda = " << lambdaPenningGlobal << " cm\n";
227
228 for (int i = nTerms; i--;) {
229 rPenning[i] = rPenningGlobal;
230 lambdaPenning[i] = lambdaPenningGlobal;
231 }
232
233 if (useDeexcitation) {
234 std::cout << m_className << "::EnablePenningTransfer:\n";
235 std::cout << " Deexcitation handling will be switched off.\n";
236 }
237 usePenning = true;
238}
239
240void MediumMagboltz::EnablePenningTransfer(const double r, const double lambda,
241 std::string gasname) {
242
243 if (r < 0. || r > 1.) {
244 std::cerr << m_className << "::EnablePenningTransfer:\n";
245 std::cerr << " Penning transfer probability must be "
246 << " in the range [0, 1].\n";
247 return;
248 }
249
250 // Get the "standard" name of this gas.
251 if (!GetGasName(gasname, gasname)) {
252 std::cerr << m_className << "::EnablePenningTransfer:\n";
253 std::cerr << " Unknown gas name.\n";
254 return;
255 }
256
257 // Look for this gas in the present gas mixture.
258 bool found = false;
259 int iGas = -1;
260 for (unsigned int i = 0; i < m_nComponents; ++i) {
261 if (gas[i] == gasname) {
262 rPenningGas[i] = r;
263 if (lambda < Small) {
264 lambdaPenningGas[i] = 0.;
265 } else {
266 lambdaPenningGas[i] = lambda;
267 }
268 found = true;
269 iGas = i;
270 break;
271 }
272 }
273
274 if (!found) {
275 std::cerr << m_className << "::EnablePenningTransfer:\n";
276 std::cerr << " Specified gas (" << gasname
277 << ") is not part of the present gas mixture.\n";
278 return;
279 }
280
281 // Make sure that the collision rate table is updated.
282 if (m_isChanged) {
283 if (!Mixer()) {
284 std::cerr << m_className << "::EnablePenningTransfer:\n";
285 std::cerr << " Error calculating the collision rates table.\n";
286 return;
287 }
288 m_isChanged = false;
289 }
290
291 int nLevelsFound = 0;
292 for (int i = nTerms; i--;) {
293 if (int(csType[i] / nCsTypes) == iGas) {
294 if (csType[i] % nCsTypes == ElectronCollisionTypeExcitation) {
295 ++nLevelsFound;
296 }
297 rPenning[i] = rPenningGas[iGas];
298 lambdaPenning[i] = lambdaPenningGas[iGas];
299 }
300 }
301
302 if (nLevelsFound > 0) {
303 std::cout << m_className << "::EnablePenningTransfer:\n";
304 std::cout << " Penning transfer parameters for " << nLevelsFound
305 << " excitation levels set to:\n";
306 std::cout << " r = " << rPenningGas[iGas] << "\n";
307 std::cout << " lambda = " << lambdaPenningGas[iGas] << " cm\n";
308 } else {
309 std::cerr << m_className << "::EnablePenningTransfer:\n";
310 std::cerr << " Specified gas (" << gasname
311 << ") has no excitation levels in the present energy range.\n";
312 }
313
314 usePenning = true;
315}
316
318
319 for (int i = nTerms; i--;) {
320 rPenning[i] = 0.;
321 lambdaPenning[i] = 0.;
322 }
323 rPenningGlobal = 0.;
325
326 for (unsigned int i = 0; i < m_nMaxGases; ++i) {
327 rPenningGas[i] = 0.;
328 lambdaPenningGas[i] = 0.;
329 }
330
331 usePenning = false;
332}
333
334void MediumMagboltz::DisablePenningTransfer(std::string gasname) {
335
336 // Get the "standard" name of this gas.
337 if (!GetGasName(gasname, gasname)) {
338 std::cerr << m_className << "::DisablePenningTransfer:\n";
339 std::cerr << " Gas " << gasname << " is not defined.\n";
340 return;
341 }
342
343 // Look for this gas in the present gas mixture.
344 bool found = false;
345 int iGas = -1;
346 for (unsigned int i = 0; i < m_nComponents; ++i) {
347 if (gas[i] == gasname) {
348 rPenningGas[i] = 0.;
349 lambdaPenningGas[i] = 0.;
350 found = true;
351 iGas = i;
352 break;
353 }
354 }
355
356 if (!found) {
357 std::cerr << m_className << "::DisablePenningTransfer:\n";
358 std::cerr << " Specified gas (" << gasname
359 << ") is not part of the present gas mixture.\n";
360 return;
361 }
362
363 int nLevelsFound = 0;
364 for (int i = nTerms; i--;) {
365 if (int(csType[i] / nCsTypes) == iGas) {
366 rPenning[i] = 0.;
367 lambdaPenning[i] = 0.;
368 } else {
369 if (csType[i] % nCsTypes == ElectronCollisionTypeExcitation &&
370 rPenning[i] > Small) {
371 ++nLevelsFound;
372 }
373 }
374 }
375
376 if (nLevelsFound <= 0) {
377 // There are no more excitation levels with r > 0.
378 std::cout << m_className << "::DisablePenningTransfer:\n";
379 std::cout << " Penning transfer globally switched off.\n";
380 usePenning = false;
381 }
382}
383
385 std::string gasname) {
386
387 if (r <= 0.) {
388 std::cerr << m_className << "::SetScalingFactor:\n";
389 std::cerr << " Incorrect value for scaling factor: " << r << "\n";
390 return;
391 }
392
393 // Get the "standard" name of this gas.
394 if (!GetGasName(gasname, gasname)) {
395 std::cerr << m_className << "::SetExcitationScalingFactor:\n";
396 std::cerr << " Unknown gas name.\n";
397 return;
398 }
399
400 // Look for this gas in the present gas mixture.
401 bool found = false;
402 for (unsigned int i = 0; i < m_nComponents; ++i) {
403 if (gas[i] == gasname) {
404 scaleExc[i] = r;
405 found = true;
406 break;
407 }
408 }
409
410 if (!found) {
411 std::cerr << m_className << "::SetExcitationScalingFactor:\n";
412 std::cerr << " Specified gas (" << gasname
413 << ") is not part of the present gas mixture.\n";
414 return;
415 }
416
417 // Make sure that the collision rate table is updated.
418 m_isChanged = true;
419}
420
421bool MediumMagboltz::Initialise(const bool verbose) {
422
423 if (!m_isChanged) {
424 if (m_debug) {
425 std::cerr << m_className << "::Initialise:\n";
426 std::cerr << " Nothing changed.\n";
427 }
428 return true;
429 }
430 if (!Mixer(verbose)) {
431 std::cerr << m_className << "::Initialise:\n";
432 std::cerr << " Error calculating the collision rates table.\n";
433 return false;
434 }
435 m_isChanged = false;
436 return true;
437}
438
440
442
443 if (m_isChanged) {
444 if (!Initialise()) return;
445 }
446
447 std::cout << m_className << "::PrintGas:\n";
448 for (int i = 0; i < nTerms; ++i) {
449 // Collision type
450 int type = csType[i] % nCsTypes;
451 int ngas = int(csType[i] / nCsTypes);
452 // Description (from Magboltz)
453 std::string descr = std::string(50, ' ');
454 for (int j = 50; j--;) descr[j] = description[i][j];
455 // Threshold energy
456 double e = rgas[ngas] * energyLoss[i];
457 std::cout << " Level " << i << ": " << descr << "\n";
458 std::cout << " Type " << type;
459 if (type == ElectronCollisionTypeElastic) {
460 std::cout << " (elastic)\n";
461 } else if (type == ElectronCollisionTypeIonisation) {
462 std::cout << " (ionisation)\n";
463 std::cout << " Ionisation threshold: " << e << " eV\n";
464 } else if (type == ElectronCollisionTypeAttachment) {
465 std::cout << " (attachment)\n";
466 } else if (type == ElectronCollisionTypeInelastic) {
467 std::cout << " (inelastic)\n";
468 std::cout << " Energy loss: " << e << " eV\n";
469 } else if (type == ElectronCollisionTypeExcitation) {
470 std::cout << " (excitation)\n";
471 std::cout << " Excitation energy: " << e << " eV\n";
472 } else if (type == ElectronCollisionTypeSuperelastic) {
473 std::cout << " (super-elastic)\n";
474 std::cout << " Energy gain: " << -e << " eV\n";
475 } else {
476 std::cout << " (unknown)\n";
477 }
478 if (type == ElectronCollisionTypeExcitation && usePenning &&
479 e > minIonPot) {
480 std::cout << " Penning transfer coefficient: " << rPenning[i]
481 << "\n";
482 } else if (type == ElectronCollisionTypeExcitation && useDeexcitation) {
483 const int idxc = iDeexcitation[i];
484 if (idxc < 0 || idxc >= nDeexcitations) {
485 std::cout << " Deexcitation cascade not implemented.\n";
486 continue;
487 }
488 if (deexcitations[idxc].osc > 0.) {
489 std::cout << " Oscillator strength: " << deexcitations[idxc].osc
490 << "\n";
491 }
492 std::cout << " Decay channels:\n";
493 for (int j = 0; j < deexcitations[idxc].nChannels; ++j) {
494 if (deexcitations[idxc].type[j] == DxcTypeRad) {
495 std::cout << " Radiative decay to ";
496 if (deexcitations[idxc].final[j] < 0) {
497 std::cout << "ground state: ";
498 } else {
499 std::cout << deexcitations[deexcitations[idxc].final[j]].label
500 << ": ";
501 }
502 } else if (deexcitations[idxc].type[j] == DxcTypeCollIon) {
503 if (deexcitations[idxc].final[j] < 0) {
504 std::cout << " Penning ionisation: ";
505 } else {
506 std::cout << " Associative ionisation: ";
507 }
508 } else if (deexcitations[idxc].type[j] == DxcTypeCollNonIon) {
509 if (deexcitations[idxc].final[j] >= 0) {
510 std::cout << " Collision-induced transition to "
511 << deexcitations[deexcitations[idxc].final[j]].label
512 << ": ";
513 } else {
514 std::cout << " Loss: ";
515 }
516 }
517 if (j == 0) {
518 std::cout << std::setprecision(5) << deexcitations[idxc].p[j] * 100.
519 << "%\n";
520 } else {
521 std::cout << std::setprecision(5) << (deexcitations[idxc].p[j] -
522 deexcitations[idxc].p[j - 1]) *
523 100. << "%\n";
524 }
525 }
526 }
527 }
528}
529
531
532 // If necessary, update the collision rates table.
533 if (m_isChanged) {
534 if (!Mixer()) {
535 std::cerr << m_className << "::GetElectronNullCollisionRate:\n";
536 std::cerr << " Error calculating the collision rates table.\n";
537 return 0.;
538 }
539 m_isChanged = false;
540 }
541
542 if (m_debug && band > 0) {
543 std::cerr << m_className << "::GetElectronNullCollisionRate:\n";
544 std::cerr << " Warning: unexpected band index.\n";
545 }
546
547 return cfNull;
548}
549
551 const int band) {
552
553 // Check if the electron energy is within the currently set range.
554 if (e <= 0.) {
555 std::cerr << m_className << "::GetElectronCollisionRate:\n";
556 std::cerr << " Electron energy must be greater than zero.\n";
557 return cfTot[0];
558 }
559 if (e > eFinal && useAutoAdjust) {
560 std::cerr << m_className << "::GetElectronCollisionRate:\n";
561 std::cerr << " Collision rate at " << e
562 << " eV is not included in the current table.\n";
563 std::cerr << " Increasing energy range to " << 1.05 * e << " eV.\n";
564 SetMaxElectronEnergy(1.05 * e);
565 }
566
567 // If necessary, update the collision rates table.
568 if (m_isChanged) {
569 if (!Mixer()) {
570 std::cerr << m_className << "::GetElectronCollisionRate:\n";
571 std::cerr << " Error calculating the collision rates table.\n";
572 return 0.;
573 }
574 m_isChanged = false;
575 }
576
577 if (m_debug && band > 0) {
578 std::cerr << m_className << "::GetElectronCollisionRate:\n";
579 std::cerr << " Warning: unexpected band index.\n";
580 }
581
582 // Get the energy interval.
583 int iE = 0;
584 if (e <= eHigh) {
585 // Linear binning
586 iE = int(e / eStep);
587 if (iE >= nEnergySteps) return cfTot[nEnergySteps - 1];
588 if (iE < 0) return cfTot[0];
589 return cfTot[iE];
590 }
591
592 // Logarithmic binning
593 const double eLog = log(e);
594 iE = int((eLog - eHighLog) / lnStep);
595 // Calculate the collision rate by log-log interpolation.
596 const double fmax = cfTotLog[iE];
597 const double fmin = iE == 0 ? log(cfTot[nEnergySteps - 1]) : cfTotLog[iE - 1];
598 const double emin = eHighLog + iE * lnStep;
599 const double f = fmin + (eLog - emin) * (fmax - fmin) / lnStep;
600 return exp(f);
601}
602
603double MediumMagboltz::GetElectronCollisionRate(const double e, const int level,
604 const int band) {
605
606 // Check if the electron energy is within the currently set range.
607 if (e <= 0.) {
608 std::cerr << m_className << "::GetElectronCollisionRate:\n";
609 std::cerr << " Electron energy must be greater than zero.\n";
610 return 0.;
611 }
612
613 // Check if the level exists.
614 if (level < 0) {
615 std::cerr << m_className << "::GetElectronCollisionRate:\n";
616 std::cerr << " Level must be greater than zero.\n";
617 return 0.;
618 } else if (level >= nTerms) {
619 std::cerr << m_className << "::GetElectronCollisionRate:\n";
620 std::cerr << " Level " << level << " does not exist.\n";
621 std::cerr << " The present gas mixture has " << nTerms
622 << " cross-section terms.\n";
623 return 0.;
624 }
625
626 // Get the total scattering rate.
627 double rate = GetElectronCollisionRate(e, band);
628 // Get the energy interval.
629 int iE = 0;
630 if (e <= eHigh) {
631 // Linear binning
632 iE = int(e / eStep);
633 if (iE >= nEnergySteps) return cfTot[nEnergySteps - 1];
634 if (level == 0) {
635 rate *= cf[iE][0];
636 } else {
637 rate *= cf[iE][level] - cf[iE][level - 1];
638 }
639 } else {
640 // Logarithmic binning
641 iE = int((log(e) - eHighLog) / lnStep);
642 if (level == 0) {
643 rate *= cfLog[iE][0];
644 } else {
645 rate *= cfLog[iE][level] - cfLog[iE][level - 1];
646 }
647 }
648 return rate;
649}
650
651bool MediumMagboltz::GetElectronCollision(const double e, int& type, int& level,
652 double& e1, double& dx, double& dy,
653 double& dz, int& nion, int& ndxc,
654 int& band) {
655
656 // Check if the electron energy is within the currently set range.
657 if (e > eFinal && useAutoAdjust) {
658 std::cerr << m_className << "::GetElectronCollision:\n";
659 std::cerr << " Provided electron energy (" << e
660 << " eV) exceeds current energy range (" << eFinal << " eV).\n";
661 std::cerr << " Increasing energy range to " << 1.05 * e << " eV.\n";
662 SetMaxElectronEnergy(1.05 * e);
663 } else if (e <= 0.) {
664 std::cerr << m_className << "::GetElectronCollision:\n";
665 std::cerr << " Electron energy must be greater than zero.\n";
666 return false;
667 }
668
669 // If necessary, update the collision rates table.
670 if (m_isChanged) {
671 if (!Mixer()) {
672 std::cerr << m_className << "::GetElectronCollision:\n";
673 std::cerr << " Error calculating the collision rates table.\n";
674 return false;
675 }
676 m_isChanged = false;
677 }
678
679 if (m_debug && band > 0) {
680 std::cerr << m_className << "::GetElectronCollision:\n";
681 std::cerr << " Warning: unexpected band index.\n";
682 }
683
684 double angCut = 1.;
685 double angPar = 0.5;
686
687 if (e <= eHigh) {
688 // Linear binning
689 // Get the energy interval.
690 int iE = int(e / eStep);
691 if (iE >= nEnergySteps) iE = nEnergySteps - 1;
692 if (iE < 0) iE = 0;
693
694 // Sample the scattering process.
695 const double r = RndmUniform();
696 int iLow = 0;
697 int iUp = nTerms - 1;
698 if (r <= cf[iE][iLow]) {
699 level = iLow;
700 } else if (r >= cf[iE][iUp]) {
701 level = iUp;
702 } else {
703 int iMid;
704 while (iUp - iLow > 1) {
705 iMid = (iLow + iUp) >> 1;
706 if (r < cf[iE][iMid]) {
707 iUp = iMid;
708 } else {
709 iLow = iMid;
710 }
711 }
712 level = iUp;
713 }
714 // Get the angular distribution parameters.
715 angCut = scatCut[iE][level];
716 angPar = scatParameter[iE][level];
717 } else {
718 // Logarithmic binning
719 // Get the energy interval.
720 int iE = int(log(e / eHigh) / lnStep);
721 if (iE < 0) iE = 0;
722 if (iE >= nEnergyStepsLog) iE = nEnergyStepsLog - 1;
723 // Sample the scattering process.
724 const double r = RndmUniform();
725 int iLow = 0;
726 int iUp = nTerms - 1;
727 if (r <= cfLog[iE][iLow]) {
728 level = iLow;
729 } else if (r >= cfLog[iE][iUp]) {
730 level = iUp;
731 } else {
732 int iMid;
733 while (iUp - iLow > 1) {
734 iMid = (iLow + iUp) >> 1;
735 if (r < cfLog[iE][iMid]) {
736 iUp = iMid;
737 } else {
738 iLow = iMid;
739 }
740 }
741 level = iUp;
742 }
743 // Get the angular distribution parameters.
744 angCut = scatCutLog[iE][level];
745 angPar = scatParameterLog[iE][level];
746 }
747
748 // Extract the collision type.
749 type = csType[level] % nCsTypes;
750 const int igas = int(csType[level] / nCsTypes);
751 // Increase the collision counters.
752 ++nCollisions[type];
753 ++nCollisionsDetailed[level];
754
755 // Get the energy loss for this process.
756 double loss = energyLoss[level];
757 nion = ndxc = 0;
758
759 if (type == ElectronCollisionTypeIonisation) {
760 // Sample the secondary electron energy according to
761 // the Opal-Beaty-Peterson parameterisation.
762 double esec = 0.;
763 if (useOpalBeaty) {
764 // Get the splitting parameter.
765 const double w = wOpalBeaty[level];
766 esec = w * tan(RndmUniform() * atan(0.5 * (e - loss) / w));
767 // Rescaling (SST)
768 // esec = w * pow(esec / w, 0.9524);
769 } else if (useGreenSawada) {
770 const double w = gsGreenSawada[igas] * e / (e + gbGreenSawada[igas]);
771 const double esec0 =
772 tsGreenSawada[igas] - taGreenSawada[igas] / (e + tbGreenSawada[igas]);
773 const double r = RndmUniform();
774 esec = esec0 + w * tan((r - 1.) * atan(esec0 / w) +
775 r * atan((0.5 * (e - loss) - esec0) / w));
776 } else {
777 esec = RndmUniform() * (e - loss);
778 }
779 if (esec <= 0) esec = Small;
780 loss += esec;
781 ionProducts.clear();
782 // Add the secondary electron.
783 ionProd newIonProd;
784 newIonProd.type = IonProdTypeElectron;
785 newIonProd.energy = esec;
786 ionProducts.push_back(newIonProd);
787 // Add the ion.
788 newIonProd.type = IonProdTypeIon;
789 newIonProd.energy = 0.;
790 ionProducts.push_back(newIonProd);
791 nIonisationProducts = nion = 2;
792 } else if (type == ElectronCollisionTypeExcitation) {
793 // if (gas[igas] == "CH4" && loss * rgas[igas] < 13.35 && e > 12.65) {
794 // if (RndmUniform() < 0.5) {
795 // loss = 8.55 + RndmUniform() * (13.3 - 8.55);
796 // loss /= rgas[igas];
797 // } else {
798 // loss = std::max(Small, RndmGaussian(loss * rgas[igas], 1.));
799 // loss /= rgas[igas];
800 // }
801 // }
802 // Follow the de-excitation cascade (if switched on).
803 if (useDeexcitation && iDeexcitation[level] >= 0) {
804 int fLevel = 0;
805 ComputeDeexcitationInternal(iDeexcitation[level], fLevel);
806 ndxc = nDeexcitationProducts;
807 } else if (usePenning) {
808 nDeexcitationProducts = 0;
809 dxcProducts.clear();
810 // Simplified treatment of Penning ionisation.
811 // If the energy threshold of this level exceeds the
812 // ionisation potential of one of the gases,
813 // create a new electron (with probability rPenning).
814 if (energyLoss[level] * rgas[igas] > minIonPot &&
815 RndmUniform() < rPenning[level]) {
816 // The energy of the secondary electron is assumed to be given by
817 // the difference of excitation and ionisation threshold.
818 double esec = energyLoss[level] * rgas[igas] - minIonPot;
819 if (esec <= 0) esec = Small;
820 // Add the secondary electron to the list.
821 dxcProd newDxcProd;
822 newDxcProd.t = 0.;
823 newDxcProd.s = 0.;
824 if (lambdaPenning[level] > Small) {
825 // Uniform distribution within a sphere of radius lambda
826 newDxcProd.s = lambdaPenning[level] * pow(RndmUniformPos(), 1. / 3.);
827 }
828 newDxcProd.energy = esec;
829 newDxcProd.type = DxcProdTypeElectron;
830 dxcProducts.push_back(newDxcProd);
831 nDeexcitationProducts = ndxc = 1;
832 ++nPenning;
833 }
834 }
835 }
836
837 // Make sure the energy loss is smaller than the energy.
838 if (e < loss) loss = e - 0.0001;
839
840 // Determine the scattering angle.
841 double ctheta0 = 1. - 2. * RndmUniform();
842 if (useAnisotropic) {
843 switch (scatModel[level]) {
844 case 0:
845 break;
846 case 1:
847 ctheta0 = 1. - RndmUniform() * angCut;
848 if (RndmUniform() > angPar) ctheta0 = -ctheta0;
849 break;
850 case 2:
851 ctheta0 = (ctheta0 + angPar) / (1. + angPar * ctheta0);
852 break;
853 default:
854 std::cerr << m_className << "::GetElectronCollision:\n";
855 std::cerr << " Unknown scattering model. \n";
856 std::cerr << " Using isotropic distribution.\n";
857 break;
858 }
859 }
860
861 const double s1 = rgas[igas];
862 const double s2 = (s1 * s1) / (s1 - 1.);
863 const double theta0 = acos(ctheta0);
864 const double arg = std::max(1. - s1 * loss / e, Small);
865 const double d = 1. - ctheta0 * sqrt(arg);
866
867 // Update the energy.
868 e1 = std::max(e * (1. - loss / (s1 * e) - 2. * d / s2), Small);
869 double q = std::min(sqrt((e / e1) * arg) / s1, 1.);
870 const double theta = asin(q * sin(theta0));
871 double ctheta = cos(theta);
872 if (ctheta0 < 0.) {
873 const double u = (s1 - 1.) * (s1 - 1.) / arg;
874 if (ctheta0 * ctheta0 > u) ctheta = -ctheta;
875 }
876 const double stheta = sin(theta);
877 // Calculate the direction after the collision.
878 dz = std::min(dz, 1.);
879 const double argZ = sqrt(dx * dx + dy * dy);
880
881 // Azimuth is chosen at random.
882 const double phi = TwoPi * RndmUniform();
883 const double cphi = cos(phi);
884 const double sphi = sin(phi);
885
886 if (argZ == 0.) {
887 dz = ctheta;
888 dx = cphi * stheta;
889 dy = sphi * stheta;
890 } else {
891 const double a = stheta / argZ;
892 const double dz1 = dz * ctheta + argZ * stheta * sphi;
893 const double dy1 = dy * ctheta + a * (dx * cphi - dy * dz * sphi);
894 const double dx1 = dx * ctheta - a * (dy * cphi + dx * dz * sphi);
895 dz = dz1;
896 dy = dy1;
897 dx = dx1;
898 }
899
900 return true;
901}
902
903bool MediumMagboltz::GetDeexcitationProduct(const int i, double& t, double& s,
904 int& type, double& energy) {
905
906 if (i < 0 || i >= nDeexcitationProducts || !(useDeexcitation || usePenning))
907 return false;
908 t = dxcProducts[i].t;
909 s = dxcProducts[i].s;
910 type = dxcProducts[i].type;
911 energy = dxcProducts[i].energy;
912 return true;
913}
914
915bool MediumMagboltz::GetIonisationProduct(const int i, int& type,
916 double& energy) {
917
918 if (i < 0 || i >= nIonisationProducts) {
919 std::cerr << m_className << "::GetIonisationProduct:\n";
920 std::cerr << " Index out of range.\n";
921 return false;
922 }
923
924 type = ionProducts[i].type;
925 energy = ionProducts[i].energy;
926 return true;
927}
928
930
931 if (e <= 0.) {
932 std::cerr << m_className << "::GetPhotonCollisionRate:\n";
933 std::cerr << " Photon energy must be greater than zero.\n";
934 return cfTotGamma[0];
935 }
936 if (e > eFinalGamma && useAutoAdjust) {
937 std::cerr << m_className << "::GetPhotonCollisionRate:\n";
938 std::cerr << " Collision rate at " << e
939 << " eV is not included in the current table.\n";
940 std::cerr << " Increasing energy range to " << 1.05 * e << " eV.\n";
941 SetMaxPhotonEnergy(1.05 * e);
942 }
943
944 if (m_isChanged) {
945 if (!Mixer()) {
946 std::cerr << m_className << "::GetPhotonCollisionRate:\n";
947 std::cerr << " Error calculating the collision rates table.\n";
948 return 0.;
949 }
950 m_isChanged = false;
951 }
952
953 int iE = int(e / eStepGamma);
954 if (iE >= nEnergyStepsGamma) iE = nEnergyStepsGamma - 1;
955 if (iE < 0) iE = 0;
956
957 double cfSum = cfTotGamma[iE];
958 if (useDeexcitation && useRadTrap && nDeexcitations > 0) {
959 // Loop over the excitations.
960 for (int i = nDeexcitations; i--;) {
961 if (deexcitations[i].cf > 0. &&
962 fabs(e - deexcitations[i].energy) <= deexcitations[i].width) {
963 cfSum +=
964 deexcitations[i].cf * TMath::Voigt(e - deexcitations[i].energy,
965 deexcitations[i].sDoppler,
966 2 * deexcitations[i].gPressure);
967 }
968 }
969 }
970
971 return cfSum;
972}
973
974bool MediumMagboltz::GetPhotonCollision(const double e, int& type, int& level,
975 double& e1, double& ctheta, int& nsec,
976 double& esec) {
977
978 if (e > eFinalGamma && useAutoAdjust) {
979 std::cerr << m_className << "::GetPhotonCollision:\n";
980 std::cerr << " Provided electron energy (" << e
981 << " eV) exceeds current energy range (" << eFinalGamma
982 << " eV).\n";
983 std::cerr << " Increasing energy range to " << 1.05 * e << " eV.\n";
984 SetMaxPhotonEnergy(1.05 * e);
985 } else if (e <= 0.) {
986 std::cerr << m_className << "::GetPhotonCollision:\n";
987 std::cerr << " Photon energy must be greater than zero.\n";
988 return false;
989 }
990
991 if (m_isChanged) {
992 if (!Mixer()) {
993 std::cerr << m_className << "::GetPhotonCollision:\n";
994 std::cerr << " Error calculating the collision rates table.\n";
995 return false;
996 }
997 m_isChanged = false;
998 }
999
1000 // Energy interval
1001 int iE = int(e / eStepGamma);
1002 if (iE >= nEnergyStepsGamma) iE = nEnergyStepsGamma - 1;
1003 if (iE < 0) iE = 0;
1004
1005 double r = cfTotGamma[iE];
1006 if (useDeexcitation && useRadTrap && nDeexcitations > 0) {
1007 int nLines = 0;
1008 std::vector<double> pLine(0);
1009 std::vector<int> iLine(0);
1010 // Loop over the excitations.
1011 for (int i = nDeexcitations; i--;) {
1012 if (deexcitations[i].cf > 0. &&
1013 fabs(e - deexcitations[i].energy) <= deexcitations[i].width) {
1014 r += deexcitations[i].cf * TMath::Voigt(e - deexcitations[i].energy,
1015 deexcitations[i].sDoppler,
1016 2 * deexcitations[i].gPressure);
1017 pLine.push_back(r);
1018 iLine.push_back(i);
1019 ++nLines;
1020 }
1021 }
1022 r *= RndmUniform();
1023 if (nLines > 0 && r >= cfTotGamma[iE]) {
1024 // Photon is absorbed by a discrete line.
1025 for (int i = 0; i < nLines; ++i) {
1026 if (r <= pLine[i]) {
1027 ++nPhotonCollisions[PhotonCollisionTypeExcitation];
1028 int fLevel = 0;
1029 ComputeDeexcitationInternal(iLine[i], fLevel);
1030 type = PhotonCollisionTypeExcitation;
1031 nsec = nDeexcitationProducts;
1032 return true;
1033 }
1034 }
1035 std::cerr << m_className << "::GetPhotonCollision:\n";
1036 std::cerr << " Random sampling of deexcitation line failed.\n";
1037 std::cerr << " Program bug!\n";
1038 return false;
1039 }
1040 } else {
1041 r *= RndmUniform();
1042 }
1043
1044 int iLow = 0;
1045 int iUp = nPhotonTerms - 1;
1046 if (r <= cfGamma[iE][iLow]) {
1047 level = iLow;
1048 } else if (r >= cfGamma[iE][iUp]) {
1049 level = iUp;
1050 } else {
1051 int iMid;
1052 while (iUp - iLow > 1) {
1053 iMid = (iLow + iUp) >> 1;
1054 if (r < cfGamma[iE][iMid]) {
1055 iUp = iMid;
1056 } else {
1057 iLow = iMid;
1058 }
1059 }
1060 level = iUp;
1061 }
1062
1063 nsec = 0;
1064 esec = e1 = 0.;
1065 type = csTypeGamma[level];
1066 // Collision type
1067 type = type % nCsTypesGamma;
1068 int ngas = int(csTypeGamma[level] / nCsTypesGamma);
1069 ++nPhotonCollisions[type];
1070 // Ionising collision
1071 if (type == 1) {
1072 esec = e - ionPot[ngas];
1073 if (esec < Small) esec = Small;
1074 nsec = 1;
1075 }
1076
1077 // Determine the scattering angle
1078 ctheta = 2 * RndmUniform() - 1.;
1079
1080 return true;
1081}
1082
1084
1085 for (int j = nCsTypes; j--;) nCollisions[j] = 0;
1086 nCollisionsDetailed.resize(nTerms);
1087 for (int j = nTerms; j--;) nCollisionsDetailed[j] = 0;
1088 nPenning = 0;
1089 for (int j = nCsTypesGamma; j--;) nPhotonCollisions[j] = 0;
1090}
1091
1093
1094 int ncoll = 0;
1095 for (int j = nCsTypes; j--;) ncoll += nCollisions[j];
1096 return ncoll;
1097}
1098
1100 int& nElastic, int& nIonisation, int& nAttachment, int& nInelastic,
1101 int& nExcitation, int& nSuperelastic) const {
1102
1103 nElastic = nCollisions[ElectronCollisionTypeElastic];
1104 nIonisation = nCollisions[ElectronCollisionTypeIonisation];
1105 nAttachment = nCollisions[ElectronCollisionTypeAttachment];
1106 nInelastic = nCollisions[ElectronCollisionTypeInelastic];
1107 nExcitation = nCollisions[ElectronCollisionTypeExcitation];
1108 nSuperelastic = nCollisions[ElectronCollisionTypeSuperelastic];
1109 return nElastic + nIonisation + nAttachment + nInelastic + nExcitation +
1110 nSuperelastic;
1111}
1112
1114
1115 if (m_isChanged) {
1116 if (!Mixer()) {
1117 std::cerr << m_className << "::GetNumberOfLevels:\n";
1118 std::cerr << " Error calculating the collision rates table.\n";
1119 return 0;
1120 }
1121 m_isChanged = false;
1122 }
1123
1124 return nTerms;
1125}
1126
1127bool MediumMagboltz::GetLevel(const int i, int& ngas, int& type,
1128 std::string& descr, double& e) {
1129
1130 if (m_isChanged) {
1131 if (!Mixer()) {
1132 std::cerr << m_className << "::GetLevel:\n";
1133 std::cerr << " Error calculating the collision rates table.\n";
1134 return false;
1135 }
1136 m_isChanged = false;
1137 }
1138
1139 if (i < 0 || i >= nTerms) {
1140 std::cerr << m_className << "::GetLevel:\n";
1141 std::cerr << " Requested level (" << i << ") does not exist.\n";
1142 return false;
1143 }
1144
1145 // Collision type
1146 type = csType[i] % nCsTypes;
1147 ngas = int(csType[i] / nCsTypes);
1148 // Description (from Magboltz)
1149 descr = std::string(50, ' ');
1150 for (int j = 50; j--;) descr[j] = description[i][j];
1151 // Threshold energy
1152 e = rgas[ngas] * energyLoss[i];
1153 if (m_debug) {
1154 std::cout << m_className << "::GetLevel:\n";
1155 std::cout << " Level " << i << ": " << descr << "\n";
1156 std::cout << " Type " << type << "\n",
1157 std::cout << " Threshold energy: " << e << " eV\n";
1158 if (type == ElectronCollisionTypeExcitation && usePenning &&
1159 e > minIonPot) {
1160 std::cout << " Penning transfer coefficient: " << rPenning[i] << "\n";
1161 } else if (type == ElectronCollisionTypeExcitation && useDeexcitation) {
1162 const int idxc = iDeexcitation[i];
1163 if (idxc < 0 || idxc >= nDeexcitations) {
1164 std::cout << " Deexcitation cascade not implemented.\n";
1165 return true;
1166 }
1167 if (deexcitations[idxc].osc > 0.) {
1168 std::cout << " Oscillator strength: " << deexcitations[idxc].osc
1169 << "\n";
1170 }
1171 std::cout << " Decay channels:\n";
1172 for (int j = 0; j < deexcitations[idxc].nChannels; ++j) {
1173 if (deexcitations[idxc].type[j] == DxcTypeRad) {
1174 std::cout << " Radiative decay to ";
1175 if (deexcitations[idxc].final[j] < 0) {
1176 std::cout << "ground state: ";
1177 } else {
1178 std::cout << deexcitations[deexcitations[idxc].final[j]].label
1179 << ": ";
1180 }
1181 } else if (deexcitations[idxc].type[j] == DxcTypeCollIon) {
1182 if (deexcitations[idxc].final[j] < 0) {
1183 std::cout << " Penning ionisation: ";
1184 } else {
1185 std::cout << " Associative ionisation: ";
1186 }
1187 } else if (deexcitations[idxc].type[j] == DxcTypeCollNonIon) {
1188 if (deexcitations[idxc].final[j] >= 0) {
1189 std::cout << " Collision-induced transition to "
1190 << deexcitations[deexcitations[idxc].final[j]].label
1191 << ": ";
1192 } else {
1193 std::cout << " Loss: ";
1194 }
1195 }
1196 if (j == 0) {
1197 std::cout << std::setprecision(5) << deexcitations[idxc].p[j] * 100.
1198 << "%\n";
1199 } else {
1200 std::cout << std::setprecision(5) << (deexcitations[idxc].p[j] -
1201 deexcitations[idxc].p[j - 1]) *
1202 100. << "%\n";
1203 }
1204 }
1205 }
1206 }
1207
1208 return true;
1209}
1210
1212
1213 if (level < 0 || level >= nTerms) {
1214 std::cerr << m_className << "::GetNumberOfElectronCollisions:\n";
1215 std::cerr << " Requested cross-section term (" << level
1216 << ") does not exist.\n";
1217 return 0;
1218 }
1219 return nCollisionsDetailed[level];
1220}
1221
1223
1224 int ncoll = 0;
1225 for (int j = nCsTypesGamma; j--;) ncoll += nPhotonCollisions[j];
1226 return ncoll;
1227}
1228
1229int MediumMagboltz::GetNumberOfPhotonCollisions(int& nElastic, int& nIonising,
1230 int& nInelastic) const {
1231
1232 nElastic = nPhotonCollisions[0];
1233 nIonising = nPhotonCollisions[1];
1234 nInelastic = nPhotonCollisions[2];
1235 return nElastic + nIonising + nInelastic;
1236}
1237
1238bool MediumMagboltz::GetGasNumberMagboltz(const std::string input,
1239 int& number) const {
1240
1241 if (input == "") {
1242 number = 0;
1243 return false;
1244 }
1245
1246 // CF4
1247 if (input == "CF4") {
1248 number = 1;
1249 return true;
1250 }
1251 // Argon
1252 if (input == "Ar") {
1253 number = 2;
1254 return true;
1255 }
1256 // Helium 4
1257 if (input == "He" || input == "He-4") {
1258 number = 3;
1259 return true;
1260 }
1261 // Helium 3
1262 if (input == "He-3") {
1263 number = 4;
1264 return true;
1265 }
1266 // Neon
1267 if (input == "Ne") {
1268 number = 5;
1269 return true;
1270 }
1271 // Krypton
1272 if (input == "Kr") {
1273 number = 6;
1274 return true;
1275 }
1276 // Xenon
1277 if (input == "Xe") {
1278 number = 7;
1279 return true;
1280 }
1281 // Methane
1282 if (input == "CH4") {
1283 number = 8;
1284 return true;
1285 }
1286 // Ethane
1287 if (input == "C2H6") {
1288 number = 9;
1289 return true;
1290 }
1291 // Propane
1292 if (input == "C3H8") {
1293 number = 10;
1294 return true;
1295 }
1296 // Isobutane
1297 if (input == "iC4H10") {
1298 number = 11;
1299 return true;
1300 }
1301 // Carbon dioxide (CO2)
1302 if (input == "CO2") {
1303 number = 12;
1304 return true;
1305 }
1306 // Neopentane
1307 if (input == "neoC5H12") {
1308 number = 13;
1309 return true;
1310 }
1311 // Water
1312 if (input == "H2O") {
1313 number = 14;
1314 return true;
1315 }
1316 // Oxygen
1317 if (input == "O2") {
1318 number = 15;
1319 return true;
1320 }
1321 // Nitrogen
1322 if (input == "N2") {
1323 number = 16;
1324 return true;
1325 }
1326 // Nitric oxide (NO)
1327 if (input == "NO") {
1328 number = 17;
1329 return true;
1330 }
1331 // Nitrous oxide (N2O)
1332 if (input == "N2O") {
1333 number = 18;
1334 return true;
1335 }
1336 // Ethene (C2H4)
1337 if (input == "C2H4") {
1338 number = 19;
1339 return true;
1340 }
1341 // Acetylene (C2H2)
1342 if (input == "C2H2") {
1343 number = 20;
1344 return true;
1345 }
1346 // Hydrogen
1347 if (input == "H2") {
1348 number = 21;
1349 return true;
1350 }
1351 // Deuterium
1352 if (input == "D2") {
1353 number = 22;
1354 return true;
1355 }
1356 // Carbon monoxide (CO)
1357 if (input == "CO") {
1358 number = 23;
1359 return true;
1360 }
1361 // Methylal (dimethoxymethane, CH3-O-CH2-O-CH3, "hot" version)
1362 if (input == "Methylal") {
1363 number = 24;
1364 return true;
1365 }
1366 // DME
1367 if (input == "DME") {
1368 number = 25;
1369 return true;
1370 }
1371 // Reid step
1372 if (input == "Reid-Step") {
1373 number = 26;
1374 return true;
1375 }
1376 // Maxwell model
1377 if (input == "Maxwell-Model") {
1378 number = 27;
1379 return true;
1380 }
1381 // Reid ramp
1382 if (input == "Reid-Ramp") {
1383 number = 28;
1384 return true;
1385 }
1386 // C2F6
1387 if (input == "C2F6") {
1388 number = 29;
1389 return true;
1390 }
1391 // SF6
1392 if (input == "SF6") {
1393 number = 30;
1394 return true;
1395 }
1396 // NH3
1397 if (input == "NH3") {
1398 number = 31;
1399 return true;
1400 }
1401 // Propene
1402 if (input == "C3H6") {
1403 number = 32;
1404 return true;
1405 }
1406 // Cyclopropane
1407 if (input == "cC3H6") {
1408 number = 33;
1409 return true;
1410 }
1411 // Methanol
1412 if (input == "CH3OH") {
1413 number = 34;
1414 return true;
1415 }
1416 // Ethanol
1417 if (input == "C2H5OH") {
1418 number = 35;
1419 return true;
1420 }
1421 // Propanol
1422 if (input == "C3H7OH") {
1423 number = 36;
1424 return true;
1425 }
1426 // Cesium / Caesium.
1427 if (input == "Cs") {
1428 number = 37;
1429 return true;
1430 }
1431 // Fluorine
1432 if (input == "F2") {
1433 number = 38;
1434 return true;
1435 }
1436 if (input == "CS2") {
1437 number = 39;
1438 return true;
1439 }
1440 // COS
1441 if (input == "COS") {
1442 number = 40;
1443 return true;
1444 }
1445 // Deuterated methane
1446 if (input == "CD4") {
1447 number = 41;
1448 return true;
1449 }
1450 // BF3
1451 if (input == "BF3") {
1452 number = 42;
1453 return true;
1454 }
1455 // C2H2F4 (C2HF5).
1456 if (input == "C2HF5" || input == "C2H2F4") {
1457 number = 43;
1458 return true;
1459 }
1460 // TMA
1461 if (input == "TMA") {
1462 number = 44;
1463 return true;
1464 }
1465 // CHF3
1466 if (input == "CHF3") {
1467 number = 50;
1468 return true;
1469 }
1470 // CF3Br
1471 if (input == "CF3Br") {
1472 number = 51;
1473 return true;
1474 }
1475 // C3F8
1476 if (input == "C3F8") {
1477 number = 52;
1478 return true;
1479 }
1480 // Ozone
1481 if (input == "O3") {
1482 number = 53;
1483 return true;
1484 }
1485 // Mercury
1486 if (input == "Hg") {
1487 number = 54;
1488 return true;
1489 }
1490 // H2S
1491 if (input == "H2S") {
1492 number = 55;
1493 return true;
1494 }
1495 // n-Butane
1496 if (input == "nC4H10") {
1497 number = 56;
1498 return true;
1499 }
1500 // n-Pentane
1501 if (input == "nC5H12") {
1502 number = 57;
1503 return true;
1504 }
1505 // Nitrogen
1506 if (input == "N2 (Phelps)") {
1507 number = 58;
1508 return true;
1509 }
1510 // Germane, GeH4
1511 if (input == "GeH4") {
1512 number = 59;
1513 return true;
1514 }
1515 // Silane, SiH4
1516 if (input == "SiH4") {
1517 number = 60;
1518 return true;
1519 }
1520
1521 std::cerr << m_className << "::GetGasNumberMagboltz:\n";
1522 std::cerr << " Gas " << input << " is not defined.\n";
1523 return false;
1524}
1525
1526bool MediumMagboltz::Mixer(const bool verbose) {
1527
1528 // Set constants and parameters in Magboltz common blocks.
1529 Magboltz::cnsts_.echarg = ElementaryCharge * 1.e-15;
1530 Magboltz::cnsts_.emass = ElectronMassGramme;
1531 Magboltz::cnsts_.amu = AtomicMassUnit;
1532 Magboltz::cnsts_.pir2 = BohrRadius * BohrRadius * Pi;
1533 Magboltz::inpt_.ary = RydbergEnergy;
1534
1535 Magboltz::inpt_.akt = BoltzmannConstant * m_temperature;
1536 Magboltz::inpt_.tempc = m_temperature - ZeroCelsius;
1538
1540 Magboltz::inpt_.nStep = nEnergySteps;
1541 if (useAnisotropic) {
1542 Magboltz::inpt_.nAniso = 2;
1543 } else {
1544 Magboltz::inpt_.nAniso = 0;
1545 }
1546
1547 // Calculate the atomic density (ideal gas law).
1548 const double dens = GetNumberDensity();
1549 // Prefactor for calculation of scattering rate from cross-section.
1550 const double prefactor = dens * SpeedOfLight * sqrt(2. / ElectronMass);
1551
1552 // Fill the electron energy array, reset the collision rates.
1553 for (int i = nEnergySteps; i--;) {
1554 cfTot[i] = 0.;
1555 for (int j = nMaxLevels; j--;) {
1556 cf[i][j] = 0.;
1557 scatParameter[i][j] = 0.5;
1558 scatCut[i][j] = 1.;
1559 }
1560 }
1561 for (int i = nEnergyStepsLog; i--;) {
1562 cfTotLog[i] = 0.;
1563 for (int j = nMaxLevels; j--;) {
1564 cfLog[i][j] = 0.;
1565 scatParameter[i][j] = 0.5;
1566 scatCut[i][j] = 1.;
1567 }
1568 }
1569
1570 nDeexcitations = 0;
1571 deexcitations.clear();
1572 for (int i = nMaxLevels; i--;) {
1573 scatModel[i] = 0;
1574 iDeexcitation[i] = -1;
1575 wOpalBeaty[i] = 1.;
1576 }
1577
1578 minIonPot = -1.;
1579 for (unsigned int i = 0; i < m_nMaxGases; ++i) {
1580 ionPot[i] = -1.;
1581 gsGreenSawada[i] = 1.;
1582 gbGreenSawada[i] = 0.;
1583 tsGreenSawada[i] = 0.;
1584 taGreenSawada[i] = 0.;
1585 tbGreenSawada[i] = 0.;
1586 m_hasGreenSawada[i] = false;
1587 }
1588 // Cross-sections
1589 // 0: total, 1: elastic,
1590 // 2: ionisation, 3: attachment,
1591 // 4, 5: unused
1592 static double q[nEnergySteps][6];
1593 // Parameters for scattering angular distribution
1594 static double pEqEl[nEnergySteps][6];
1595 // Inelastic cross-sections
1596 static double qIn[nEnergySteps][nMaxInelasticTerms];
1597 // Ionisation cross-sections
1598 static double qIon[nEnergySteps][8];
1599 // Parameters for angular distribution in inelastic collisions
1600 static double pEqIn[nEnergySteps][nMaxInelasticTerms];
1601 // Parameters for angular distribution in ionising collisions
1602 static double pEqIon[nEnergySteps][8];
1603 // Opal-Beaty parameter
1604 static double eoby[nEnergySteps];
1605 // Penning transfer parameters
1606 static double penFra[nMaxInelasticTerms][3];
1607 // Description of cross-section terms
1608 static char scrpt[260][50];
1609
1610 // Check the gas composition and establish the gas numbers.
1611 int gasNumber[m_nMaxGases];
1612 for (unsigned int i = 0; i < m_nComponents; ++i) {
1613 if (!GetGasNumberMagboltz(gas[i], gasNumber[i])) {
1614 std::cerr << m_className << "::Mixer:\n";
1615 std::cerr << " Gas " << gas[i] << " has no corresponding"
1616 << " gas number in Magboltz.\n";
1617 return false;
1618 }
1619 }
1620
1621 if (m_debug || verbose) {
1622 std::cout << m_className << "::Mixer:\n";
1623 std::cout << " Creating table of collision rates with\n";
1624 std::cout << " " << nEnergySteps << " linear energy steps between 0 and "
1625 << std::min(eFinal, eHigh) << " eV\n";
1626 if (eFinal > eHigh) {
1627 std::cout << " " << nEnergyStepsLog
1628 << " logarithmic energy steps between " << eHigh << " and "
1629 << eFinal << " eV\n";
1630 }
1631 }
1632 nTerms = 0;
1633
1634 std::ofstream outfile;
1635 if (useCsOutput) {
1636 outfile.open("cs.txt", std::ios::out);
1637 outfile << "# energy [eV] vs. cross-section [cm2]\n";
1638 }
1639
1640 // Loop over the gases in the mixture.
1641 for (unsigned int iGas = 0; iGas < m_nComponents; ++iGas) {
1642 if (eFinal <= eHigh) {
1643 Magboltz::inpt_.efinal = eFinal;
1644 } else {
1645 Magboltz::inpt_.efinal = eHigh;
1646 }
1647 Magboltz::inpt_.estep = eStep;
1648
1649 // Number of inelastic cross-section terms
1650 long long nIn = 0;
1651 long long nIon = 0;
1652 // Threshold energies
1653 double e[6] = {0., 0., 0., 0., 0., 0.};
1654 double eIn[nMaxInelasticTerms] = {0.};
1655 double eIon[8] = {0.};
1656 // Virial coefficient (not used)
1657 double virial = 0.;
1658 // Scattering algorithms
1659 long long kIn[nMaxInelasticTerms] = {0};
1660 long long kEl[6] = {0, 0, 0, 0, 0, 0};
1661 char name[] = " ";
1662
1663 // Retrieve the cross-section data for this gas from Magboltz.
1664 long long ngs = gasNumber[iGas];
1665 Magboltz::gasmix_(&ngs, q[0], qIn[0], &nIn, e, eIn, name, &virial, eoby,
1666 pEqEl[0], pEqIn[0], penFra[0], kEl, kIn, qIon[0],
1667 pEqIon[0], eIon, &nIon, scrpt);
1668 if (m_debug || verbose) {
1669 const double massAmu =
1670 (2. / e[1]) * ElectronMass / AtomicMassUnitElectronVolt;
1671 std::cout << " " << name << "\n";
1672 std::cout << " mass: " << massAmu << " amu\n";
1673 if (nIon > 1) {
1674 std::cout << " ionisation threshold: " << eIon[0] << " eV\n";
1675 } else {
1676 std::cout << " ionisation threshold: " << e[2] << " eV\n";
1677 }
1678 if (e[3] > 0. && e[4] > 0.) {
1679 std::cout << " cross-sections at minimum ionising energy:\n";
1680 std::cout << " excitation: " << e[3] * 1.e18 << " Mbarn\n";
1681 std::cout << " ionisation: " << e[4] * 1.e18 << " Mbarn\n";
1682 }
1683 }
1684 int np0 = nTerms;
1685
1686 // Make sure there is still sufficient space.
1687 if (np0 + nIn + nIon + 1 >= nMaxLevels) {
1688 std::cerr << m_className << "::Mixer:\n";
1689 std::cerr << " Max. number of levels (" << nMaxLevels
1690 << ") exceeded.\n";
1691 return false;
1692 }
1693
1694 double van = fraction[iGas] * prefactor;
1695
1696 int np = np0;
1697 if (useCsOutput) {
1698 outfile << "# cross-sections for " << name << "\n";
1699 outfile << "# cross-section types:\n";
1700 outfile << "# elastic\n";
1701 }
1702 // Elastic scattering
1703 ++nTerms;
1704 scatModel[np] = kEl[1];
1705 const double r = 1. + e[1] / 2.;
1706 rgas[iGas] = r;
1707 energyLoss[np] = 0.;
1708 for (int j = 0; j < 50; ++j) {
1709 description[np][j] = scrpt[1][j];
1710 }
1711 csType[np] = nCsTypes * iGas + ElectronCollisionTypeElastic;
1712 bool withIon = false;
1713 // Ionisation
1714 if (nIon > 1) {
1715 for (int j = 0; j < nIon; ++j) {
1716 if (eFinal < eIon[j]) continue;
1717 withIon = true;
1718 ++nTerms;
1719 ++np;
1720 scatModel[np] = kEl[2];
1721 energyLoss[np] = eIon[j] / r;
1722 // TODO
1723 wOpalBeaty[np] = eoby[j];
1724 if (gas[iGas] == "CH4") {
1725 if (fabs(eIon[j] - 21.) < 0.1) {
1726 wOpalBeaty[np] = 14.;
1727 } else if (fabs(eIon[j] - 291.) < 0.1) {
1728 wOpalBeaty[np] = 200.;
1729 }
1730 }
1731 for (int k = 0; k < 50; ++k) {
1732 description[np][k] = scrpt[2 + j][k];
1733 }
1734 csType[np] = nCsTypes * iGas + ElectronCollisionTypeIonisation;
1735 if (useCsOutput) {
1736 outfile << "# " << description[np] << "\n";
1737 }
1738 }
1739 gsGreenSawada[iGas] = eoby[0];
1740 tbGreenSawada[iGas] = 2 * eIon[0];
1741 ionPot[iGas] = eIon[0];
1742 } else {
1743 if (eFinal >= e[2]) {
1744 withIon = true;
1745 ++nTerms;
1746 ++np;
1747 scatModel[np] = kEl[2];
1748 energyLoss[np] = e[2] / r;
1749 wOpalBeaty[np] = eoby[0];
1750 gsGreenSawada[iGas] = eoby[0];
1751 tbGreenSawada[iGas] = 2 * e[2];
1752 ionPot[iGas] = e[2];
1753 for (int j = 0; j < 50; ++j) {
1754 description[np][j] = scrpt[2][j];
1755 }
1756 csType[np] = nCsTypes * iGas + ElectronCollisionTypeIonisation;
1757 if (useCsOutput) {
1758 outfile << "# ionisation (gross)\n";
1759 }
1760 }
1761 }
1762 // Attachment
1763 ++nTerms;
1764 ++np;
1765 scatModel[np] = 0;
1766 energyLoss[np] = 0.;
1767 for (int j = 0; j < 50; ++j) {
1768 description[np][j] = scrpt[2 + nIon][j];
1769 }
1770 csType[np] = nCsTypes * iGas + ElectronCollisionTypeAttachment;
1771 if (useCsOutput) {
1772 outfile << "# attachment\n";
1773 }
1774 // Inelastic terms
1775 int nExc = 0, nSuperEl = 0;
1776 for (int j = 0; j < nIn; ++j) {
1777 ++np;
1778 scatModel[np] = kIn[j];
1779 energyLoss[np] = eIn[j] / r;
1780 for (int k = 0; k < 50; ++k) {
1781 description[np][k] = scrpt[5 + nIon + j][k];
1782 }
1783 if ((description[np][1] == 'E' && description[np][2] == 'X') ||
1784 (description[np][0] == 'E' && description[np][1] == 'X') ||
1785 (gas[iGas] == "N2" && eIn[j] > 6.)) {
1786 // Excitation
1787 csType[np] = nCsTypes * iGas + ElectronCollisionTypeExcitation;
1788 ++nExc;
1789 } else if (eIn[j] < 0.) {
1790 // Super-elastic collision
1791 csType[np] = nCsTypes * iGas + ElectronCollisionTypeSuperelastic;
1792 ++nSuperEl;
1793 } else {
1794 // Inelastic collision
1795 csType[np] = nCsTypes * iGas + ElectronCollisionTypeInelastic;
1796 }
1797 if (useCsOutput) {
1798 outfile << "# " << description[np] << "\n";
1799 }
1800 }
1801 nTerms += nIn;
1802 // Loop over the energy table.
1803 for (int iE = 0; iE < nEnergySteps; ++iE) {
1804 np = np0;
1805 if (useCsOutput) {
1806 outfile << (iE + 0.5) * eStep << " " << q[iE][1] << " ";
1807 }
1808 // Elastic scattering
1809 cf[iE][np] = q[iE][1] * van;
1810 if (scatModel[np] == 1) {
1811 ComputeAngularCut(pEqEl[iE][1], scatCut[iE][np], scatParameter[iE][np]);
1812 } else if (scatModel[np] == 2) {
1813 scatParameter[iE][np] = pEqEl[iE][1];
1814 }
1815 // Ionisation
1816 if (withIon) {
1817 if (nIon > 1) {
1818 for (int j = 0; j < nIon; ++j) {
1819 if (eFinal < eIon[j]) continue;
1820 ++np;
1821 cf[iE][np] = qIon[iE][j] * van;
1822 if (scatModel[np] == 1) {
1823 ComputeAngularCut(pEqIon[iE][j], scatCut[iE][np],
1824 scatParameter[iE][np]);
1825 } else if (scatModel[np] == 2) {
1826 scatParameter[iE][np] = pEqIon[iE][j];
1827 }
1828 if (useCsOutput) {
1829 outfile << qIon[iE][j] << " ";
1830 }
1831 }
1832 } else {
1833 ++np;
1834 cf[iE][np] = q[iE][2] * van;
1835 if (scatModel[np] == 1) {
1836 ComputeAngularCut(pEqEl[iE][2], scatCut[iE][np],
1837 scatParameter[iE][np]);
1838 } else if (scatModel[np] == 2) {
1839 scatParameter[iE][np] = pEqEl[iE][2];
1840 }
1841 if (useCsOutput) {
1842 outfile << q[iE][2] << " ";
1843 }
1844 }
1845 }
1846 // Attachment
1847 ++np;
1848 cf[iE][np] = q[iE][3] * van;
1849 scatParameter[iE][np] = 0.5;
1850 if (useCsOutput) {
1851 outfile << q[iE][3] << " ";
1852 }
1853 // Inelastic terms
1854 for (int j = 0; j < nIn; ++j) {
1855 ++np;
1856 if (useCsOutput) outfile << qIn[iE][j] << " ";
1857 cf[iE][np] = qIn[iE][j] * van;
1858 // Scale the excitation cross-sections (for error estimates).
1859 cf[iE][np] *= scaleExc[iGas];
1860 // Temporary hack for methane dissociative excitations:
1861 if (description[np][5] == 'D' && description[np][6] == 'I' &&
1862 description[np][7] == 'S') {
1863 // if ((iE + 0.5) * eStep > 40.) {
1864 // cf[iE][np] *= 0.8;
1865 // } else if ((iE + 0.5) * eStep > 30.) {
1866 // cf[iE][np] *= (1. - ((iE + 0.5) * eStep - 30.) * 0.02);
1867 // }
1868 }
1869 if (cf[iE][np] < 0.) {
1870 std::cerr << m_className << "::Mixer:\n";
1871 std::cerr << " Negative inelastic cross-section at "
1872 << (iE + 0.5) * eStep << " eV.\n";
1873 std::cerr << " Set to zero.\n";
1874 cf[iE][np] = 0.;
1875 }
1876 if (scatModel[np] == 1) {
1877 ComputeAngularCut(pEqIn[iE][j], scatCut[iE][np],
1878 scatParameter[iE][np]);
1879 } else if (scatModel[np] == 2) {
1880 scatParameter[iE][np] = pEqIn[iE][j];
1881 }
1882 }
1883 if ((m_debug || verbose) && nIn > 0 && iE == nEnergySteps - 1) {
1884 std::cout << " " << nIn << " inelastic terms (" << nExc
1885 << " excitations, " << nSuperEl << " superelastic, "
1886 << nIn - nExc - nSuperEl << " other)\n";
1887 }
1888 if (useCsOutput) outfile << "\n";
1889 }
1890
1891 if (eFinal <= eHigh) continue;
1892 // Fill the high-energy part (logarithmic binning).
1893 // Calculate the growth factor.
1894 const double rLog = pow(eFinal / eHigh, 1. / nEnergyStepsLog);
1895 lnStep = log(rLog);
1896 // Set the upper limit of the first bin.
1897 double emax = eHigh * rLog;
1898 int imax = nEnergySteps - 1;
1899 for (int iE = 0; iE < nEnergyStepsLog; ++iE) {
1900 Magboltz::inpt_.estep = emax / (nEnergySteps - 0.5);
1901 Magboltz::inpt_.efinal = emax + 0.5 * Magboltz::inpt_.estep;
1902 Magboltz::gasmix_(&ngs, q[0], qIn[0], &nIn, e, eIn, name, &virial, eoby,
1903 pEqEl[0], pEqIn[0], penFra[0], kEl, kIn, qIon[0],
1904 pEqIon[0], eIon, &nIon, scrpt);
1905 np = np0;
1906 if (useCsOutput) {
1907 outfile << emax << " " << q[imax][1] << " ";
1908 }
1909 // Elastic scattering
1910 cfLog[iE][np] = q[imax][1] * van;
1911 if (scatModel[np] == 1) {
1912 ComputeAngularCut(pEqEl[imax][1], scatCutLog[iE][np],
1913 scatParameterLog[iE][np]);
1914 } else if (scatModel[np] == 2) {
1915 scatParameterLog[iE][np] = pEqEl[imax][1];
1916 }
1917 // Ionisation
1918 if (withIon) {
1919 if (nIon > 1) {
1920 for (int j = 0; j < nIon; ++j) {
1921 if (eFinal < eIon[j]) continue;
1922 ++np;
1923 cfLog[iE][np] = qIon[imax][j] * van;
1924 if (scatModel[np] == 1) {
1925 ComputeAngularCut(pEqIon[imax][j], scatCutLog[iE][np],
1926 scatParameterLog[iE][np]);
1927 } else if (scatModel[np] == 2) {
1928 scatParameterLog[iE][np] = pEqIon[imax][j];
1929 }
1930 if (useCsOutput) {
1931 outfile << qIon[imax][j] << " ";
1932 }
1933 }
1934 } else {
1935 ++np;
1936 // Gross cross-section
1937 cfLog[iE][np] = q[imax][2] * van;
1938 // Counting cross-section
1939 // cfLog[iE][np] = q[imax][4] * van;
1940 if (scatModel[np] == 1) {
1941 ComputeAngularCut(pEqEl[imax][2], scatCutLog[iE][np],
1942 scatParameterLog[iE][np]);
1943 } else if (scatModel[np] == 2) {
1944 scatParameterLog[iE][np] = pEqEl[imax][2];
1945 }
1946 }
1947 }
1948 // Attachment
1949 ++np;
1950 cfLog[iE][np] = q[imax][3] * van;
1951 if (useCsOutput) {
1952 outfile << q[imax][3] << " ";
1953 }
1954 // Inelastic terms
1955 for (int j = 0; j < nIn; ++j) {
1956 ++np;
1957 if (useCsOutput) outfile << qIn[imax][j] << " ";
1958 cfLog[iE][np] = qIn[imax][j] * van;
1959 // Scale the excitation cross-sections (for error estimates).
1960 cfLog[iE][np] *= scaleExc[iGas];
1961 if (cfLog[iE][np] < 0.) {
1962 std::cerr << m_className << "::Mixer:\n";
1963 std::cerr << " Negative inelastic cross-section at " << emax
1964 << " eV.\n";
1965 std::cerr << " Set to zero.\n";
1966 cfLog[iE][np] = 0.;
1967 }
1968 if (scatModel[np] == 1) {
1969 ComputeAngularCut(pEqIn[imax][j], scatCutLog[iE][np],
1970 scatParameterLog[iE][np]);
1971 } else if (scatModel[np] == 2) {
1972 scatParameterLog[iE][np] = pEqIn[imax][j];
1973 }
1974 }
1975 if (useCsOutput) outfile << "\n";
1976 // Increase the energy.
1977 emax *= rLog;
1978 }
1979 }
1980 if (useCsOutput) outfile.close();
1981
1982 // Find the smallest ionisation threshold.
1983 std::string minIonPotGas = "";
1984 for (unsigned int i = 0; i < m_nMaxGases; ++i) {
1985 if (ionPot[i] < 0.) continue;
1986 if (minIonPot < 0.) {
1987 minIonPot = ionPot[i];
1988 minIonPotGas = gas[i];
1989 } else if (ionPot[i] < minIonPot) {
1990 minIonPot = ionPot[i];
1991 minIonPotGas = gas[i];
1992 }
1993 }
1994
1995 if (m_debug || verbose) {
1996 std::cout << m_className << "::Mixer:\n";
1997 std::cout << " Lowest ionisation threshold in the mixture:\n";
1998 std::cout << " " << minIonPot << " eV (" << minIonPotGas << ")\n";
1999 }
2000
2001 for (int iE = nEnergySteps; iE--;) {
2002 // Calculate the total collision frequency.
2003 for (int k = nTerms; k--;) {
2004 if (cf[iE][k] < 0.) {
2005 std::cerr << m_className << "::Mixer:\n";
2006 std::cerr << " Negative collision rate at " << (iE + 0.5) * eStep
2007 << " eV. \n";
2008 std::cerr << " Set to zero.\n";
2009 cf[iE][k] = 0.;
2010 }
2011 cfTot[iE] += cf[iE][k];
2012 }
2013 // Normalise the collision probabilities.
2014 if (cfTot[iE] > 0.) {
2015 for (int k = nTerms; k--;) cf[iE][k] /= cfTot[iE];
2016 }
2017 for (int k = 1; k < nTerms; ++k) {
2018 cf[iE][k] += cf[iE][k - 1];
2019 }
2020 const double ekin = eStep * (iE + 0.5);
2021 cfTot[iE] *= sqrt(ekin);
2022 // Use relativistic expression at high energies.
2023 if (ekin > 1.e3) {
2024 cfTot[iE] *=
2025 sqrt(1. + 0.5 * ekin / ElectronMass) / (1. + ekin / ElectronMass);
2026 }
2027 }
2028
2029 if (eFinal > eHigh) {
2030 const double rLog = pow(eFinal / eHigh, 1. / nEnergyStepsLog);
2031 for (int iE = nEnergyStepsLog; iE--;) {
2032 // Calculate the total collision frequency.
2033 for (int k = nTerms; k--;) {
2034 if (cfLog[iE][k] < 0.) {
2035 cfLog[iE][k] = 0.;
2036 }
2037 cfTotLog[iE] += cfLog[iE][k];
2038 }
2039 // Normalise the collision probabilities.
2040 if (cfTotLog[iE] > 0.) {
2041 for (int k = nTerms; k--;) cfLog[iE][k] /= cfTotLog[iE];
2042 }
2043 for (int k = 1; k < nTerms; ++k) {
2044 cfLog[iE][k] += cfLog[iE][k - 1];
2045 }
2046 const double ekin = eHigh * pow(rLog, iE + 1);
2047 cfTotLog[iE] *= sqrt(ekin) * sqrt(1. + 0.5 * ekin / ElectronMass) /
2048 (1. + ekin / ElectronMass);
2049 // Store the logarithm (for log-log interpolation)
2050 cfTotLog[iE] = log(cfTotLog[iE]);
2051 }
2052 }
2053
2054 // Determine the null collision frequency.
2055 cfNull = 0.;
2056 for (int j = 0; j < nEnergySteps; ++j) {
2057 if (cfTot[j] > cfNull) cfNull = cfTot[j];
2058 }
2059 if (eFinal > eHigh) {
2060 for (int j = 0; j < nEnergyStepsLog; ++j) {
2061 const double r = exp(cfTotLog[j]);
2062 if (r > cfNull) cfNull = r;
2063 }
2064 }
2065
2066 // Reset the collision counters.
2067 nCollisionsDetailed.resize(nTerms);
2068 for (int j = nCsTypes; j--;) nCollisions[j] = 0;
2069 for (int j = nTerms; j--;) nCollisionsDetailed[j] = 0;
2070
2071 if (m_debug || verbose) {
2072 std::cout << m_className << "::Mixer:\n";
2073 std::cout << " Energy [eV] Collision Rate [ns-1]\n";
2074 for (int i = 0; i < 8; ++i) {
2075 const double emax = std::min(eHigh, eFinal);
2076 std::cout << " " << std::fixed << std::setw(10) << std::setprecision(2)
2077 << (2 * i + 1) * emax / 16 << " " << std::setw(18)
2078 << std::setprecision(2) << cfTot[(i + 1) * nEnergySteps / 16]
2079 << "\n";
2080 }
2081 std::cout << std::resetiosflags(std::ios_base::floatfield);
2082 }
2083
2084 // Set up the de-excitation channels.
2085 if (useDeexcitation) {
2086 ComputeDeexcitationTable(verbose);
2087 const int dxcCount = deexcitations.size();
2088 if (dxcCount != nDeexcitations) {
2089 std::cerr << m_className << "::Mixer:\n";
2090 std::cerr << " Mismatch in deexcitation count.\n";
2091 std::cerr << " Program bug!\n";
2092 std::cerr << " Deexcitation handling is switched off.\n";
2093 useDeexcitation = false;
2094 } else {
2095 for (int j = nDeexcitations; j--;) {
2096 const int probCount = deexcitations[j].p.size();
2097 const int flvlCount = deexcitations[j].final.size();
2098 const int typeCount = deexcitations[j].type.size();
2099 if (!(probCount == flvlCount && flvlCount == typeCount &&
2100 typeCount == deexcitations[j].nChannels)) {
2101 std::cerr << m_className << "::Mixer:\n";
2102 std::cerr << " Mismatch in deexcitation channel count.\n";
2103 std::cerr << " Program bug!\n";
2104 std::cerr << " Deexcitation handling is switched off.\n";
2105 useDeexcitation = false;
2106 }
2107 }
2108 }
2109 }
2110
2111 // Fill the photon collision rates table.
2112 if (!ComputePhotonCollisionTable(verbose)) {
2113 std::cerr << m_className << "::Mixer:\n";
2114 std::cerr << " Photon collision rates could not be calculated.\n";
2115 if (useDeexcitation) {
2116 std::cerr << " Deexcitation handling is switched off.\n";
2117 useDeexcitation = false;
2118 }
2119 }
2120
2121 // Reset the Penning transfer parameters.
2122 for (int i = nTerms; i--;) {
2123 rPenning[i] = rPenningGlobal;
2124 int iGas = int(csType[i] / nCsTypes);
2125 if (rPenningGas[iGas] > Small) {
2126 rPenning[i] = rPenningGas[iGas];
2127 lambdaPenning[i] = lambdaPenningGas[iGas];
2128 }
2129 }
2130
2131 // Set the Green-Sawada splitting function parameters.
2132 SetupGreenSawada();
2133
2134 return true;
2135}
2136
2137void MediumMagboltz::SetupGreenSawada() {
2138
2139 for (unsigned int i = 0; i < m_nComponents; ++i) {
2140 taGreenSawada[i] = 1000.;
2141 m_hasGreenSawada[i] = true;
2142 if (gas[i] == "He" || gas[i] == "He-3") {
2143 tsGreenSawada[i] = -2.25;
2144 gsGreenSawada[i] = 15.5;
2145 gbGreenSawada[i] = 24.5;
2146 } else if (gas[i] == "Ne") {
2147 tsGreenSawada[i] = -6.49;
2148 gsGreenSawada[i] = 24.3;
2149 gbGreenSawada[i] = 21.6;
2150 } else if (gas[i] == "Ar") {
2151 tsGreenSawada[i] = 6.87;
2152 gsGreenSawada[i] = 6.92;
2153 gbGreenSawada[i] = 7.85;
2154 } else if (gas[i] == "Kr") {
2155 tsGreenSawada[i] = 3.90;
2156 gsGreenSawada[i] = 7.95;
2157 gbGreenSawada[i] = 13.5;
2158 } else if (gas[i] == "Xe") {
2159 tsGreenSawada[i] = 3.81;
2160 gsGreenSawada[i] = 7.93;
2161 gbGreenSawada[i] = 11.5;
2162 } else if (gas[i] == "H2" || gas[i] == "D2") {
2163 tsGreenSawada[i] = 1.87;
2164 gsGreenSawada[i] = 7.07;
2165 gbGreenSawada[i] = 7.7;
2166 } else if (gas[i] == "N2") {
2167 tsGreenSawada[i] = 4.71;
2168 gsGreenSawada[i] = 13.8;
2169 gbGreenSawada[i] = 15.6;
2170 } else if (gas[i] == "O2") {
2171 tsGreenSawada[i] = 1.86;
2172 gsGreenSawada[i] = 18.5;
2173 gbGreenSawada[i] = 12.1;
2174 } else if (gas[i] == "CH4") {
2175 tsGreenSawada[i] = 3.45;
2176 gsGreenSawada[i] = 7.06;
2177 gbGreenSawada[i] = 12.5;
2178 } else if (gas[i] == "H20") {
2179 tsGreenSawada[i] = 1.28;
2180 gsGreenSawada[i] = 12.8;
2181 gbGreenSawada[i] = 12.6;
2182 } else if (gas[i] == "CO") {
2183 tsGreenSawada[i] = 2.03;
2184 gsGreenSawada[i] = 13.3;
2185 gbGreenSawada[i] = 14.0;
2186 } else if (gas[i] == "C2H2") {
2187 tsGreenSawada[i] = 1.37;
2188 gsGreenSawada[i] = 9.28;
2189 gbGreenSawada[i] = 5.8;
2190 } else if (gas[i] == "NO") {
2191 tsGreenSawada[i] = -4.30;
2192 gsGreenSawada[i] = 10.4;
2193 gbGreenSawada[i] = 9.5;
2194 } else if (gas[i] == "CO2") {
2195 tsGreenSawada[i] = -2.46;
2196 gsGreenSawada[i] = 12.3;
2197 gbGreenSawada[i] = 13.8;
2198 } else {
2199 taGreenSawada[i] = 0.;
2200 m_hasGreenSawada[i] = false;
2201 if (useGreenSawada) {
2202 std::cout << m_className << "::SetupGreenSawada:\n";
2203 std::cout << " Fit parameters for " << gas[i] << " not available.\n";
2204 std::cout << " Opal-Beaty formula is used instead.\n";
2205 }
2206 }
2207 }
2208}
2209
2210void MediumMagboltz::ComputeAngularCut(double parIn, double& cut,
2211 double& parOut) {
2212
2213 // Set cuts on angular distribution and
2214 // renormalise forward scattering probability.
2215
2216 if (parIn <= 1.) {
2217 cut = 1.;
2218 parOut = parIn;
2219 return;
2220 }
2221
2222 const double rads = 2. / Pi;
2223 const double cns = parIn - 0.5;
2224 const double thetac = asin(2. * sqrt(cns - cns * cns));
2225 const double fac = (1. - cos(thetac)) / pow(sin(thetac), 2.);
2226 parOut = cns * fac + 0.5;
2227 cut = thetac * rads;
2228}
2229
2230void MediumMagboltz::ComputeDeexcitationTable(const bool verbose) {
2231
2232 for (int i = nMaxLevels; i--;) iDeexcitation[i] = -1;
2233 deexcitations.clear();
2234 nDeexcitations = 0;
2235
2236 // Optical data (for quencher photoabsorption cs and ionisation yield)
2237 OpticalData optData;
2238
2239 // Presence flags, concentrations and indices of "de-excitable" gases.
2240 bool withAr = false;
2241 int iAr = 0;
2242 double cAr = 0.;
2243 bool withNe = false;
2244
2245 std::map<std::string, int> mapLevels;
2246 // Make a mapping of all excitation levels.
2247 for (int i = 0; i < nTerms; ++i) {
2248 // Check if the level is an excitation.
2249 if (csType[i] % nCsTypes != ElectronCollisionTypeExcitation) continue;
2250 // Extract the index of the gas.
2251 const int ngas = int(csType[i] / nCsTypes);
2252 if (gas[ngas] == "Ar") {
2253 // Argon
2254 if (!withAr) {
2255 withAr = true;
2256 iAr = ngas;
2257 cAr = fraction[iAr];
2258 }
2259 // Get the level description (as specified in Magboltz).
2260 std::string level = " ";
2261 for (int j = 0; j < 7; ++j) level[j] = description[i][5 + j];
2262 if (level == "1S5 ")
2263 mapLevels["Ar_1S5"] = i;
2264 else if (level == "1S4 ")
2265 mapLevels["Ar_1S4"] = i;
2266 else if (level == "1S3 ")
2267 mapLevels["Ar_1S3"] = i;
2268 else if (level == "1S2 ")
2269 mapLevels["Ar_1S2"] = i;
2270 else if (level == "2P10 ")
2271 mapLevels["Ar_2P10"] = i;
2272 else if (level == "2P9 ")
2273 mapLevels["Ar_2P9"] = i;
2274 else if (level == "2P8 ")
2275 mapLevels["Ar_2P8"] = i;
2276 else if (level == "2P7 ")
2277 mapLevels["Ar_2P7"] = i;
2278 else if (level == "2P6 ")
2279 mapLevels["Ar_2P6"] = i;
2280 else if (level == "2P5 ")
2281 mapLevels["Ar_2P5"] = i;
2282 else if (level == "2P4 ")
2283 mapLevels["Ar_2P4"] = i;
2284 else if (level == "2P3 ")
2285 mapLevels["Ar_2P3"] = i;
2286 else if (level == "2P2 ")
2287 mapLevels["Ar_2P2"] = i;
2288 else if (level == "2P1 ")
2289 mapLevels["Ar_2P1"] = i;
2290 else if (level == "3D6 ")
2291 mapLevels["Ar_3D6"] = i;
2292 else if (level == "3D5 ")
2293 mapLevels["Ar_3D5"] = i;
2294 else if (level == "3D3 ")
2295 mapLevels["Ar_3D3"] = i;
2296 else if (level == "3D4! ")
2297 mapLevels["Ar_3D4!"] = i;
2298 else if (level == "3D4 ")
2299 mapLevels["Ar_3D4"] = i;
2300 else if (level == "3D1!! ")
2301 mapLevels["Ar_3D1!!"] = i;
2302 else if (level == "2S5 ")
2303 mapLevels["Ar_2S5"] = i;
2304 else if (level == "2S4 ")
2305 mapLevels["Ar_2S4"] = i;
2306 else if (level == "3D1! ")
2307 mapLevels["Ar_3D1!"] = i;
2308 else if (level == "3D2 ")
2309 mapLevels["Ar_3D2"] = i;
2310 else if (level == "3S1!!!!")
2311 mapLevels["Ar_3S1!!!!"] = i;
2312 else if (level == "3S1!! ")
2313 mapLevels["Ar_3S1!!"] = i;
2314 else if (level == "3S1!!! ")
2315 mapLevels["Ar_3S1!!!"] = i;
2316 else if (level == "2S3 ")
2317 mapLevels["Ar_2S3"] = i;
2318 else if (level == "2S2 ")
2319 mapLevels["Ar_2S2"] = i;
2320 else if (level == "3S1! ")
2321 mapLevels["Ar_3S1!"] = i;
2322 else if (level == "4D5 ")
2323 mapLevels["Ar_4D5"] = i;
2324 else if (level == "3S4 ")
2325 mapLevels["Ar_3S4"] = i;
2326 else if (level == "4D2 ")
2327 mapLevels["Ar_4D2"] = i;
2328 else if (level == "4S1! ")
2329 mapLevels["Ar_4S1!"] = i;
2330 else if (level == "3S2 ")
2331 mapLevels["Ar_3S2"] = i;
2332 else if (level == "5D5 ")
2333 mapLevels["Ar_5D5"] = i;
2334 else if (level == "4S4 ")
2335 mapLevels["Ar_4S4"] = i;
2336 else if (level == "5D2 ")
2337 mapLevels["Ar_5D2"] = i;
2338 else if (level == "6D5 ")
2339 mapLevels["Ar_6D5"] = i;
2340 else if (level == "5S1! ")
2341 mapLevels["Ar_5S1!"] = i;
2342 else if (level == "4S2 ")
2343 mapLevels["Ar_4S2"] = i;
2344 else if (level == "5S4 ")
2345 mapLevels["Ar_5S4"] = i;
2346 else if (level == "6D2 ")
2347 mapLevels["Ar_6D2"] = i;
2348 else if (level == "HIGH ")
2349 mapLevels["Ar_Higher"] = i;
2350 else {
2351 std::cerr << m_className << "::ComputeDeexcitationTable:\n";
2352 std::cerr << " Unknown excitation level:\n";
2353 std::cerr << " Ar " << level << "\n";
2354 }
2355 } else if (gas[ngas] == "Ne") {
2356 // Neon
2357 if (!withNe) {
2358 withNe = true;
2359 }
2360 std::string level = " ";
2361 for (int j = 0; j < 7; ++j) level[j] = description[i][3 + j];
2362 if (level == " 1S5 ")
2363 mapLevels["Ne_1S5"] = i;
2364 else if (level == " 1S4 ")
2365 mapLevels["Ne_1S4"] = i;
2366 else if (level == " 1S3 ")
2367 mapLevels["Ne_1S3"] = i;
2368 else if (level == " 1S2 ")
2369 mapLevels["Ne_1S2"] = i;
2370 else if (level == " 2P10 ")
2371 mapLevels["Ne_2P10"] = i;
2372 else if (level == " 2P9 ")
2373 mapLevels["Ne_2P9"] = i;
2374 else if (level == " 2P8 ")
2375 mapLevels["Ne_2P8"] = i;
2376 else if (level == " 2P7 ")
2377 mapLevels["Ne_2P7"] = i;
2378 else if (level == " 2P6 ")
2379 mapLevels["Ne_2P6"] = i;
2380 else if (level == " 2P5 ")
2381 mapLevels["Ne_2P5"] = i;
2382 else if (level == " 2P4 ")
2383 mapLevels["Ne_2P4"] = i;
2384 else if (level == " 2P3 ")
2385 mapLevels["Ne_2P3"] = i;
2386 else if (level == " 2P2 ")
2387 mapLevels["Ne_2P2"] = i;
2388 else if (level == " 2P1 ")
2389 mapLevels["Ne_2P1"] = i;
2390 else if (level == " 2S5 ")
2391 mapLevels["Ne_2S5"] = i;
2392 else if (level == " 2S4 ")
2393 mapLevels["Ne_2S4"] = i;
2394 else if (level == " 2S3 ")
2395 mapLevels["Ne_2S3"] = i;
2396 else if (level == " 2S2 ")
2397 mapLevels["Ne_2S2"] = i;
2398 else if (level == " 3D6 ")
2399 mapLevels["Ne_3D6"] = i;
2400 else if (level == " 3D5 ")
2401 mapLevels["Ne_3D5"] = i;
2402 else if (level == " 3D4! ")
2403 mapLevels["Ne_3D4!"] = i;
2404 else if (level == " 3D4 ")
2405 mapLevels["Ne_3D4"] = i;
2406 else if (level == " 3D3 ")
2407 mapLevels["Ne_3D3"] = i;
2408 else if (level == " 3D2 ")
2409 mapLevels["Ne_3D2"] = i;
2410 else if (level == " 3D1!! ")
2411 mapLevels["Ne_3D1!!"] = i;
2412 else if (level == " 3D1! ")
2413 mapLevels["Ne_3D1!"] = i;
2414 else if (level == "3S1!!!!")
2415 mapLevels["Ne_3S1!!!!"] = i;
2416 else if (level == "3S1!!! ")
2417 mapLevels["Ne_3S1!!!"] = i;
2418 else if (level == " 3S1!! ")
2419 mapLevels["Ne_3S1!!"] = i;
2420 else if (level == " 3S1! ")
2421 mapLevels["Ne_3S1!"] = i;
2422 else if (level == "SUM 3P1")
2423 mapLevels["Ne_3P10_3P6"] = i;
2424 else if (level == "SUM 3P5")
2425 mapLevels["Ne_3P5_3P2"] = i;
2426 else if (level == " 3P1 ")
2427 mapLevels["Ne_3P1"] = i;
2428 else if (level == " 3S4 ")
2429 mapLevels["Ne_3S4"] = i;
2430 else if (level == " 3S2 ")
2431 mapLevels["Ne_3S2"] = i;
2432 else if (level == " 4D5 ")
2433 mapLevels["Ne_4D5"] = i;
2434 else if (level == " 4D2 ")
2435 mapLevels["Ne_4D2"] = i;
2436 else if (level == " 4S1! ")
2437 mapLevels["Ne_4S1!"] = i;
2438 else if (level == " 4S4 ")
2439 mapLevels["Ne_4S4"] = i;
2440 else if (level == " 5D5 ")
2441 mapLevels["Ne_5D5"] = i;
2442 else if (level == " 5D2 ")
2443 mapLevels["Ne_5D2"] = i;
2444 else if (level == " 4S2 ")
2445 mapLevels["Ne_4S2"] = i;
2446 else if (level == " 5S1! ")
2447 mapLevels["Ne_5S1!"] = i;
2448 else if (level == "SUM S H")
2449 mapLevels["Ne_Sum_S_High"] = i;
2450 else if (level == "SUM D H")
2451 mapLevels["Ne_Sum_P_High"] = i;
2452 else {
2453 std::cerr << m_className << "::ComputeDeexcitationTable:\n";
2454 std::cerr << " Unknown excitation level:\n";
2455 std::cerr << " Ne " << level << "\n";
2456 }
2457 break;
2458 }
2459 }
2460
2461 // Count the excitation levels.
2462 std::map<std::string, int> mapDxc;
2463 std::map<std::string, int>::iterator itMap;
2464 for (itMap = mapLevels.begin(); itMap != mapLevels.end(); itMap++) {
2465 std::string level = (*itMap).first;
2466 mapDxc[level] = nDeexcitations;
2467 iDeexcitation[(*itMap).second] = nDeexcitations;
2468 ++nDeexcitations;
2469 }
2470
2471 // Conversion factor from oscillator strength to transition rate.
2472 const double f2A =
2473 2. * SpeedOfLight * FineStructureConstant / (3. * ElectronMass * HbarC);
2474
2475 // Radiative de-excitation channels
2476 // Transition rates (unless indicated otherwise) are taken from:
2477 // NIST Atomic Spectra Database
2478 // Transition rates for lines missing in the NIST database:
2479 // O. Zatsarinny and K. Bartschat, J. Phys. B 39 (2006), 2145-2158
2480 // Oscillator strengths not included in the NIST database:
2481 // J. Berkowitz, Atomic and Molecular Photoabsorption (2002)
2482 // C.-M. Lee and K. T. Lu, Phys. Rev. A 8 (1973), 1241-1257
2483 deexcitation newDxc;
2484 for (itMap = mapLevels.begin(); itMap != mapLevels.end(); itMap++) {
2485 std::string level = (*itMap).first;
2486 newDxc.gas = int(csType[(*itMap).second] / nCsTypes);
2487 newDxc.level = (*itMap).second;
2488 newDxc.label = level;
2489 // Excitation energy
2490 newDxc.energy = energyLoss[(*itMap).second] * rgas[newDxc.gas];
2491 // Oscillator strength
2492 newDxc.osc = newDxc.cf = 0.;
2493 newDxc.sDoppler = newDxc.gPressure = newDxc.width = 0.;
2494 newDxc.p.clear();
2495 newDxc.final.clear();
2496 newDxc.type.clear();
2497 newDxc.nChannels = 0;
2498 if (level == "Ar_1S5" || level == "Ar_1S3") {
2499 // Metastables
2500 } else if (level == "Ar_1S4") {
2501 // Oscillator strength from NIST database
2502 newDxc.osc = 0.0609;
2503 // Berkowitz: f = 0.058
2504 int nc = 1;
2505 newDxc.nChannels = nc;
2506 newDxc.p.resize(nc);
2507 newDxc.final.resize(nc);
2508 newDxc.type.resize(nc, DxcTypeRad);
2509 newDxc.p[0] = 0.119;
2510 newDxc.final[0] = -1;
2511 } else if (level == "Ar_1S2") {
2512 // Oscillator strength from NIST database
2513 newDxc.osc = 0.25;
2514 // Berkowitz: 0.2214
2515 int nc = 1;
2516 newDxc.nChannels = nc;
2517 newDxc.p.resize(nc);
2518 newDxc.final.resize(nc);
2519 newDxc.type.resize(nc, DxcTypeRad);
2520 newDxc.p[0] = 0.51;
2521 newDxc.final[0] = -1;
2522 } else if (level == "Ar_2P10") {
2523 int nc = 4;
2524 newDxc.nChannels = nc;
2525 newDxc.p.resize(nc);
2526 newDxc.final.resize(nc);
2527 newDxc.type.resize(nc, DxcTypeRad);
2528 newDxc.p[0] = 0.0189;
2529 newDxc.final[0] = mapDxc["Ar_1S5"];
2530 newDxc.p[1] = 5.43e-3;
2531 newDxc.final[1] = mapDxc["Ar_1S4"];
2532 newDxc.p[2] = 9.8e-4;
2533 newDxc.final[2] = mapDxc["Ar_1S3"];
2534 newDxc.p[3] = 1.9e-4;
2535 newDxc.final[3] = mapDxc["Ar_1S2"];
2536 } else if (level == "Ar_2P9") {
2537 int nc = 1;
2538 newDxc.nChannels = nc;
2539 newDxc.p.resize(nc);
2540 newDxc.final.resize(nc);
2541 newDxc.type.resize(nc, DxcTypeRad);
2542 newDxc.p[0] = 0.0331;
2543 newDxc.final[0] = mapDxc["Ar_1S5"];
2544 } else if (level == "Ar_2P8") {
2545 int nc = 3;
2546 newDxc.nChannels = nc;
2547 newDxc.p.resize(nc);
2548 newDxc.final.resize(nc);
2549 newDxc.type.resize(nc, DxcTypeRad);
2550 newDxc.p[0] = 9.28e-3;
2551 newDxc.final[0] = mapDxc["Ar_1S5"];
2552 newDxc.p[1] = 0.0215;
2553 newDxc.final[1] = mapDxc["Ar_1S4"];
2554 newDxc.p[2] = 1.47e-3;
2555 newDxc.final[2] = mapDxc["Ar_1S2"];
2556 } else if (level == "Ar_2P7") {
2557 int nc = 4;
2558 newDxc.nChannels = nc;
2559 newDxc.p.resize(nc);
2560 newDxc.final.resize(nc);
2561 newDxc.type.resize(nc, DxcTypeRad);
2562 newDxc.p[0] = 5.18e-3;
2563 newDxc.final[0] = mapDxc["Ar_1S5"];
2564 newDxc.p[1] = 0.025;
2565 newDxc.final[1] = mapDxc["Ar_1S4"];
2566 newDxc.p[2] = 2.43e-3;
2567 newDxc.final[2] = mapDxc["Ar_1S3"];
2568 newDxc.p[3] = 1.06e-3;
2569 newDxc.final[3] = mapDxc["Ar_1S2"];
2570 } else if (level == "Ar_2P6") {
2571 int nc = 3;
2572 newDxc.nChannels = nc;
2573 newDxc.p.resize(nc);
2574 newDxc.final.resize(nc);
2575 newDxc.type.resize(nc, DxcTypeRad);
2576 newDxc.p[0] = 0.0245;
2577 newDxc.final[0] = mapDxc["Ar_1S5"];
2578 newDxc.p[1] = 4.9e-3;
2579 newDxc.final[1] = mapDxc["Ar_1S4"];
2580 newDxc.p[2] = 5.03e-3;
2581 newDxc.final[2] = mapDxc["Ar_1S2"];
2582 } else if (level == "Ar_2P5") {
2583 int nc = 1;
2584 newDxc.nChannels = nc;
2585 newDxc.p.resize(nc);
2586 newDxc.final.resize(nc);
2587 newDxc.type.resize(nc, DxcTypeRad);
2588 newDxc.p[0] = 0.0402;
2589 newDxc.final[0] = mapDxc["Ar_1S4"];
2590 } else if (level == "Ar_2P4") {
2591 int nc = 4;
2592 newDxc.nChannels = nc;
2593 newDxc.p.resize(nc);
2594 newDxc.final.resize(nc);
2595 newDxc.type.resize(nc, DxcTypeRad);
2596 newDxc.p[0] = 6.25e-4;
2597 newDxc.final[0] = mapDxc["Ar_1S5"];
2598 newDxc.p[1] = 2.2e-5;
2599 newDxc.final[1] = mapDxc["Ar_1S4"];
2600 newDxc.p[2] = 0.0186;
2601 newDxc.final[2] = mapDxc["Ar_1S3"];
2602 newDxc.p[3] = 0.0139;
2603 newDxc.final[3] = mapDxc["Ar_1S2"];
2604 } else if (level == "Ar_2P3") {
2605 int nc = 3;
2606 newDxc.nChannels = nc;
2607 newDxc.p.resize(nc);
2608 newDxc.final.resize(nc);
2609 newDxc.type.resize(nc, DxcTypeRad);
2610 newDxc.p[0] = 3.8e-3;
2611 newDxc.final[0] = mapDxc["Ar_1S5"];
2612 newDxc.p[1] = 8.47e-3;
2613 newDxc.final[1] = mapDxc["Ar_1S4"];
2614 newDxc.p[2] = 0.0223;
2615 newDxc.final[2] = mapDxc["Ar_1S2"];
2616 } else if (level == "Ar_2P2") {
2617 int nc = 4;
2618 newDxc.nChannels = nc;
2619 newDxc.p.resize(nc);
2620 newDxc.final.resize(nc);
2621 newDxc.type.resize(nc, DxcTypeRad);
2622 newDxc.p[0] = 6.39e-3;
2623 newDxc.final[0] = mapDxc["Ar_1S5"];
2624 newDxc.p[1] = 1.83e-3;
2625 newDxc.final[1] = mapDxc["Ar_1S4"];
2626 newDxc.p[2] = 0.0117;
2627 newDxc.final[2] = mapDxc["Ar_1S3"];
2628 newDxc.p[3] = 0.0153;
2629 newDxc.final[3] = mapDxc["Ar_1S2"];
2630 } else if (level == "Ar_2P1") {
2631 int nc = 2;
2632 newDxc.nChannels = nc;
2633 newDxc.p.resize(nc);
2634 newDxc.final.resize(nc);
2635 newDxc.type.resize(nc, DxcTypeRad);
2636 newDxc.p[0] = 2.36e-4;
2637 newDxc.final[0] = mapDxc["Ar_1S4"];
2638 newDxc.p[1] = 0.0445;
2639 newDxc.final[1] = mapDxc["Ar_1S2"];
2640 } else if (level == "Ar_3D6") {
2641 int nc = 4;
2642 newDxc.nChannels = nc;
2643 newDxc.p.resize(nc);
2644 newDxc.final.resize(nc);
2645 newDxc.type.resize(nc, DxcTypeRad);
2646 // Additional line (2P7) from Bartschat
2647 newDxc.p[0] = 8.1e-3;
2648 newDxc.final[0] = mapDxc["Ar_2P10"];
2649 newDxc.p[1] = 7.73e-4;
2650 newDxc.final[1] = mapDxc["Ar_2P7"];
2651 newDxc.p[2] = 1.2e-4;
2652 newDxc.final[2] = mapDxc["Ar_2P4"];
2653 newDxc.p[3] = 3.6e-4;
2654 newDxc.final[3] = mapDxc["Ar_2P2"];
2655 } else if (level == "Ar_3D5") {
2656 // Oscillator strength from Berkowitz
2657 newDxc.osc = 0.0011;
2658 int nc = 10;
2659 newDxc.nChannels = nc;
2660 newDxc.p.resize(nc);
2661 newDxc.final.resize(nc);
2662 newDxc.type.resize(nc, DxcTypeRad);
2663 // Additional lines (2P7, 2P6, 2P5, 2P1) from Bartschat
2664 newDxc.p[0] = 7.4e-3;
2665 newDxc.final[0] = mapDxc["Ar_2P10"];
2666 newDxc.p[1] = 3.9e-5;
2667 newDxc.final[1] = mapDxc["Ar_2P8"];
2668 newDxc.p[2] = 3.09e-4;
2669 newDxc.final[2] = mapDxc["Ar_2P7"];
2670 newDxc.p[3] = 1.37e-3;
2671 newDxc.final[3] = mapDxc["Ar_2P6"];
2672 newDxc.p[4] = 5.75e-4;
2673 newDxc.final[4] = mapDxc["Ar_2P5"];
2674 newDxc.p[5] = 3.2e-5;
2675 newDxc.final[5] = mapDxc["Ar_2P4"];
2676 newDxc.p[6] = 1.4e-4;
2677 newDxc.final[6] = mapDxc["Ar_2P3"];
2678 newDxc.p[7] = 1.7e-4;
2679 newDxc.final[7] = mapDxc["Ar_2P2"];
2680 newDxc.p[8] = 2.49e-6;
2681 newDxc.final[8] = mapDxc["Ar_2P1"];
2682 // Transition probability to ground state calculated from osc. strength
2683 newDxc.p[9] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
2684 newDxc.final[9] = -1;
2685 } else if (level == "Ar_3D3") {
2686 int nc = 8;
2687 newDxc.nChannels = nc;
2688 newDxc.p.resize(nc);
2689 newDxc.final.resize(nc);
2690 newDxc.type.resize(nc, DxcTypeRad);
2691 // Additional lines (2P9, 2P4) from Bartschat
2692 newDxc.p[0] = 4.9e-3;
2693 newDxc.final[0] = mapDxc["Ar_2P10"];
2694 newDxc.p[1] = 9.82e-5;
2695 newDxc.final[1] = mapDxc["Ar_2P9"];
2696 newDxc.p[2] = 1.2e-4;
2697 newDxc.final[2] = mapDxc["Ar_2P8"];
2698 newDxc.p[3] = 2.6e-4;
2699 newDxc.final[3] = mapDxc["Ar_2P7"];
2700 newDxc.p[4] = 2.5e-3;
2701 newDxc.final[4] = mapDxc["Ar_2P6"];
2702 newDxc.p[5] = 9.41e-5;
2703 newDxc.final[5] = mapDxc["Ar_2P4"];
2704 newDxc.p[6] = 3.9e-4;
2705 newDxc.final[6] = mapDxc["Ar_2P3"];
2706 newDxc.p[7] = 1.1e-4;
2707 newDxc.final[7] = mapDxc["Ar_2P2"];
2708 } else if (level == "Ar_3D4!") {
2709 int nc = 1;
2710 newDxc.nChannels = nc;
2711 // Transition probability for 2P9 transition from Bartschat
2712 newDxc.p.resize(nc);
2713 newDxc.final.resize(nc);
2714 newDxc.type.resize(nc, DxcTypeRad);
2715 newDxc.p[0] = 0.01593;
2716 newDxc.final[0] = mapDxc["Ar_2P9"];
2717 } else if (level == "Ar_3D4") {
2718 int nc = 4;
2719 newDxc.nChannels = nc;
2720 newDxc.p.resize(nc);
2721 newDxc.final.resize(nc);
2722 newDxc.type.resize(nc, DxcTypeRad);
2723 // Additional lines (2P9, 2P3) from Bartschat
2724 newDxc.p[0] = 2.29e-3;
2725 newDxc.final[0] = mapDxc["Ar_2P9"];
2726 newDxc.p[1] = 0.011;
2727 newDxc.final[1] = mapDxc["Ar_2P8"];
2728 newDxc.p[2] = 8.8e-5;
2729 newDxc.final[2] = mapDxc["Ar_2P6"];
2730 newDxc.p[3] = 2.53e-6;
2731 newDxc.final[3] = mapDxc["Ar_2P3"];
2732 } else if (level == "Ar_3D1!!") {
2733 int nc = 8;
2734 newDxc.nChannels = nc;
2735 newDxc.p.resize(nc);
2736 newDxc.final.resize(nc);
2737 newDxc.type.resize(nc, DxcTypeRad);
2738 // Additional lines (2P10, 2P6, 2P4 - 2P2) from Bartschat
2739 newDxc.p[0] = 5.85e-6;
2740 newDxc.final[0] = mapDxc["Ar_2P10"];
2741 newDxc.p[1] = 1.2e-4;
2742 newDxc.final[1] = mapDxc["Ar_2P9"];
2743 newDxc.p[2] = 5.7e-3;
2744 newDxc.final[2] = mapDxc["Ar_2P8"];
2745 newDxc.p[3] = 7.3e-3;
2746 newDxc.final[3] = mapDxc["Ar_2P7"];
2747 newDxc.p[4] = 2.e-4;
2748 newDxc.final[4] = mapDxc["Ar_2P6"];
2749 newDxc.p[5] = 1.54e-6;
2750 newDxc.final[5] = mapDxc["Ar_2P4"];
2751 newDxc.p[6] = 2.08e-5;
2752 newDxc.final[6] = mapDxc["Ar_2P3"];
2753 newDxc.p[7] = 6.75e-7;
2754 newDxc.final[7] = mapDxc["Ar_2P2"];
2755 } else if (level == "Ar_2S5") {
2756 int nc = 8;
2757 newDxc.nChannels = nc;
2758 newDxc.p.resize(nc);
2759 newDxc.final.resize(nc);
2760 newDxc.type.resize(nc, DxcTypeRad);
2761 newDxc.p[0] = 4.9e-3;
2762 newDxc.final[0] = mapDxc["Ar_2P10"];
2763 newDxc.p[1] = 0.011;
2764 newDxc.final[1] = mapDxc["Ar_2P9"];
2765 newDxc.p[2] = 1.1e-3;
2766 newDxc.final[2] = mapDxc["Ar_2P8"];
2767 newDxc.p[3] = 4.6e-4;
2768 newDxc.final[3] = mapDxc["Ar_2P7"];
2769 newDxc.p[4] = 3.3e-3;
2770 newDxc.final[4] = mapDxc["Ar_2P6"];
2771 newDxc.p[5] = 5.9e-5;
2772 newDxc.final[5] = mapDxc["Ar_2P4"];
2773 newDxc.p[6] = 1.2e-4;
2774 newDxc.final[6] = mapDxc["Ar_2P3"];
2775 newDxc.p[7] = 3.1e-4;
2776 newDxc.final[7] = mapDxc["Ar_2P2"];
2777 } else if (level == "Ar_2S4") {
2778 // Oscillator strength from NIST database
2779 newDxc.osc = 0.027;
2780 // Berkowitz: f = 0.026;
2781 int nc = 10;
2782 newDxc.nChannels = nc;
2783 newDxc.p.resize(nc);
2784 newDxc.final.resize(nc);
2785 newDxc.type.resize(nc, DxcTypeRad);
2786 newDxc.p[0] = 0.077;
2787 newDxc.final[0] = -1;
2788 newDxc.p[1] = 2.44e-3;
2789 newDxc.final[1] = mapDxc["Ar_2P10"];
2790 newDxc.p[2] = 8.9e-3;
2791 newDxc.final[2] = mapDxc["Ar_2P8"];
2792 newDxc.p[3] = 4.6e-3;
2793 newDxc.final[3] = mapDxc["Ar_2P7"];
2794 newDxc.p[4] = 2.7e-3;
2795 newDxc.final[4] = mapDxc["Ar_2P6"];
2796 newDxc.p[5] = 1.3e-3;
2797 newDxc.final[5] = mapDxc["Ar_2P5"];
2798 newDxc.p[6] = 4.5e-4;
2799 newDxc.final[6] = mapDxc["Ar_2P4"];
2800 newDxc.p[7] = 2.9e-5;
2801 newDxc.final[7] = mapDxc["Ar_2P3"];
2802 newDxc.p[8] = 3.e-5;
2803 newDxc.final[8] = mapDxc["Ar_2P2"];
2804 newDxc.p[9] = 1.6e-4;
2805 newDxc.final[9] = mapDxc["Ar_2P1"];
2806 } else if (level == "Ar_3D1!") {
2807 int nc = 4;
2808 newDxc.nChannels = nc;
2809 newDxc.p.resize(nc);
2810 newDxc.final.resize(nc);
2811 newDxc.type.resize(nc, DxcTypeRad);
2812 // Additional line (2P6) from Bartschat
2813 newDxc.p[0] = 3.1e-3;
2814 newDxc.final[0] = mapDxc["Ar_2P9"];
2815 newDxc.p[1] = 2.e-3;
2816 newDxc.final[1] = mapDxc["Ar_2P8"];
2817 newDxc.p[2] = 0.015;
2818 newDxc.final[2] = mapDxc["Ar_2P6"];
2819 newDxc.p[3] = 9.8e-6;
2820 newDxc.final[3] = mapDxc["Ar_2P3"];
2821 } else if (level == "Ar_3D2") {
2822 // Oscillator strength from NIST database
2823 newDxc.osc = 0.0932;
2824 // Berkowitz: f = 0.09
2825 int nc = 10;
2826 newDxc.nChannels = nc;
2827 newDxc.p.resize(nc);
2828 newDxc.final.resize(nc);
2829 newDxc.type.resize(nc, DxcTypeRad);
2830 // Additional lines (2P10, 2P6, 2P4-2P1) from Bartschat
2831 newDxc.p[0] = 0.27;
2832 newDxc.final[0] = -1;
2833 newDxc.p[1] = 1.35e-5;
2834 newDxc.final[1] = mapDxc["Ar_2P10"];
2835 newDxc.p[2] = 9.52e-4;
2836 newDxc.final[2] = mapDxc["Ar_2P8"];
2837 newDxc.p[3] = 0.011;
2838 newDxc.final[3] = mapDxc["Ar_2P7"];
2839 newDxc.p[4] = 4.01e-5;
2840 newDxc.final[4] = mapDxc["Ar_2P6"];
2841 newDxc.p[5] = 4.3e-3;
2842 newDxc.final[5] = mapDxc["Ar_2P5"];
2843 newDxc.p[6] = 8.96e-4;
2844 newDxc.final[6] = mapDxc["Ar_2P4"];
2845 newDxc.p[7] = 4.45e-5;
2846 newDxc.final[7] = mapDxc["Ar_2P3"];
2847 newDxc.p[8] = 5.87e-5;
2848 newDxc.final[8] = mapDxc["Ar_2P2"];
2849 newDxc.p[9] = 8.77e-4;
2850 newDxc.final[9] = mapDxc["Ar_2P1"];
2851 } else if (level == "Ar_3S1!!!!") {
2852 int nc = 8;
2853 newDxc.nChannels = nc;
2854 newDxc.p.resize(nc);
2855 newDxc.final.resize(nc);
2856 newDxc.type.resize(nc, DxcTypeRad);
2857 // Additional lines (2P10, 2P9, 2P7, 2P6, 2P2) from Bartschat
2858 newDxc.p[0] = 7.51e-6;
2859 newDxc.final[0] = mapDxc["Ar_2P10"];
2860 newDxc.p[1] = 4.3e-5;
2861 newDxc.final[1] = mapDxc["Ar_2P9"];
2862 newDxc.p[2] = 8.3e-4;
2863 newDxc.final[2] = mapDxc["Ar_2P8"];
2864 newDxc.p[3] = 5.01e-5;
2865 newDxc.final[3] = mapDxc["Ar_2P7"];
2866 newDxc.p[4] = 2.09e-4;
2867 newDxc.final[4] = mapDxc["Ar_2P6"];
2868 newDxc.p[5] = 0.013;
2869 newDxc.final[5] = mapDxc["Ar_2P4"];
2870 newDxc.p[6] = 2.2e-3;
2871 newDxc.final[6] = mapDxc["Ar_2P3"];
2872 newDxc.p[7] = 3.35e-6;
2873 newDxc.final[7] = mapDxc["Ar_2P2"];
2874 } else if (level == "Ar_3S1!!") {
2875 int nc = 8;
2876 newDxc.nChannels = nc;
2877 newDxc.p.resize(nc);
2878 newDxc.final.resize(nc);
2879 newDxc.type.resize(nc, DxcTypeRad);
2880 // Additional lines (2P10 - 2P8, 2P4, 2P3)
2881 newDxc.p[0] = 1.89e-4;
2882 newDxc.final[0] = mapDxc["Ar_2P10"];
2883 newDxc.p[1] = 1.52e-4;
2884 newDxc.final[1] = mapDxc["Ar_2P9"];
2885 newDxc.p[2] = 7.21e-4;
2886 newDxc.final[2] = mapDxc["Ar_2P8"];
2887 newDxc.p[3] = 3.69e-4;
2888 newDxc.final[3] = mapDxc["Ar_2P7"];
2889 newDxc.p[4] = 3.76e-3;
2890 newDxc.final[4] = mapDxc["Ar_2P6"];
2891 newDxc.p[5] = 1.72e-4;
2892 newDxc.final[5] = mapDxc["Ar_2P4"];
2893 newDxc.p[6] = 5.8e-4;
2894 newDxc.final[6] = mapDxc["Ar_2P3"];
2895 newDxc.p[7] = 6.2e-3;
2896 newDxc.final[7] = mapDxc["Ar_2P2"];
2897 } else if (level == "Ar_3S1!!!") {
2898 int nc = 4;
2899 newDxc.nChannels = nc;
2900 newDxc.p.resize(nc);
2901 newDxc.final.resize(nc);
2902 newDxc.type.resize(nc, DxcTypeRad);
2903 // Additional lines (2P9, 2P8, 2P6) from Bartschat
2904 newDxc.p[0] = 7.36e-4;
2905 newDxc.final[0] = mapDxc["Ar_2P9"];
2906 newDxc.p[1] = 4.2e-5;
2907 newDxc.final[1] = mapDxc["Ar_2P8"];
2908 newDxc.p[2] = 9.3e-5;
2909 newDxc.final[2] = mapDxc["Ar_2P6"];
2910 newDxc.p[3] = 0.015;
2911 newDxc.final[3] = mapDxc["Ar_2P3"];
2912 } else if (level == "Ar_2S3") {
2913 int nc = 4;
2914 newDxc.nChannels = nc;
2915 newDxc.p.resize(nc);
2916 newDxc.final.resize(nc);
2917 newDxc.type.resize(nc, DxcTypeRad);
2918 newDxc.p[0] = 3.26e-3;
2919 newDxc.final[0] = mapDxc["Ar_2P10"];
2920 newDxc.p[1] = 2.22e-3;
2921 newDxc.final[1] = mapDxc["Ar_2P7"];
2922 newDxc.p[2] = 0.01;
2923 newDxc.final[2] = mapDxc["Ar_2P4"];
2924 newDxc.p[3] = 5.1e-3;
2925 newDxc.final[3] = mapDxc["Ar_2P2"];
2926 } else if (level == "Ar_2S2") {
2927 // Oscillator strength from NIST database
2928 newDxc.osc = 0.0119;
2929 // Berkowitz: f = 0.012;
2930 int nc = 10;
2931 newDxc.nChannels = nc;
2932 newDxc.p.resize(nc);
2933 newDxc.final.resize(nc);
2934 newDxc.type.resize(nc, DxcTypeRad);
2935 newDxc.p[0] = 0.035;
2936 newDxc.final[0] = -1;
2937 newDxc.p[1] = 1.76e-3;
2938 newDxc.final[1] = mapDxc["Ar_2P10"];
2939 newDxc.p[2] = 2.1e-4;
2940 newDxc.final[2] = mapDxc["Ar_2P8"];
2941 newDxc.p[3] = 2.8e-4;
2942 newDxc.final[3] = mapDxc["Ar_2P7"];
2943 newDxc.p[4] = 1.39e-3;
2944 newDxc.final[4] = mapDxc["Ar_2P6"];
2945 newDxc.p[5] = 3.8e-4;
2946 newDxc.final[5] = mapDxc["Ar_2P5"];
2947 newDxc.p[6] = 2.0e-3;
2948 newDxc.final[6] = mapDxc["Ar_2P4"];
2949 newDxc.p[7] = 8.9e-3;
2950 newDxc.final[7] = mapDxc["Ar_2P3"];
2951 newDxc.p[8] = 3.4e-3;
2952 newDxc.final[8] = mapDxc["Ar_2P2"];
2953 newDxc.p[9] = 1.9e-3;
2954 newDxc.final[9] = mapDxc["Ar_2P1"];
2955 } else if (level == "Ar_3S1!") {
2956 // Oscillator strength from NIST database
2957 newDxc.osc = 0.106;
2958 // Berkowitz: f = 0.106
2959 int nc = 10;
2960 newDxc.nChannels = nc;
2961 newDxc.p.resize(nc);
2962 newDxc.final.resize(nc);
2963 newDxc.type.resize(nc, DxcTypeRad);
2964 // Additional lines (2P10, 2P8, 2P7, 2P3) from Bartschat
2965 newDxc.p[0] = 0.313;
2966 newDxc.final[0] = -1;
2967 newDxc.p[1] = 2.05e-5;
2968 newDxc.final[1] = mapDxc["Ar_2P10"];
2969 newDxc.p[2] = 8.33e-5;
2970 newDxc.final[2] = mapDxc["Ar_2P8"];
2971 newDxc.p[3] = 3.9e-4;
2972 newDxc.final[3] = mapDxc["Ar_2P7"];
2973 newDxc.p[4] = 3.96e-4;
2974 newDxc.final[4] = mapDxc["Ar_2P6"];
2975 newDxc.p[5] = 4.2e-4;
2976 newDxc.final[5] = mapDxc["Ar_2P5"];
2977 newDxc.p[6] = 4.5e-3;
2978 newDxc.final[6] = mapDxc["Ar_2P4"];
2979 newDxc.p[7] = 4.84e-5;
2980 newDxc.final[7] = mapDxc["Ar_2P3"];
2981 newDxc.p[8] = 7.1e-3;
2982 newDxc.final[8] = mapDxc["Ar_2P2"];
2983 newDxc.p[9] = 5.2e-3;
2984 newDxc.final[9] = mapDxc["Ar_2P1"];
2985 } else if (level == "Ar_4D5") {
2986 // Oscillator strength from Berkowitz
2987 newDxc.osc = 0.0019;
2988 int nc = 7;
2989 newDxc.nChannels = nc;
2990 newDxc.p.resize(nc);
2991 newDxc.final.resize(nc);
2992 newDxc.type.resize(nc, DxcTypeRad);
2993 newDxc.p[0] = 2.78e-3;
2994 newDxc.final[0] = mapDxc["Ar_2P10"];
2995 newDxc.p[1] = 2.8e-4;
2996 newDxc.final[1] = mapDxc["Ar_2P8"];
2997 newDxc.p[2] = 8.6e-4;
2998 newDxc.final[2] = mapDxc["Ar_2P6"];
2999 newDxc.p[3] = 9.2e-4;
3000 newDxc.final[3] = mapDxc["Ar_2P5"];
3001 newDxc.p[4] = 4.6e-4;
3002 newDxc.final[4] = mapDxc["Ar_2P3"];
3003 newDxc.p[5] = 1.6e-4;
3004 newDxc.final[5] = mapDxc["Ar_2P2"];
3005 // Transition probability to ground state calculated from osc. strength
3006 newDxc.p[6] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3007 newDxc.final[6] = -1;
3008 } else if (level == "Ar_3S4") {
3009 // Oscillator strength from Berkowitz
3010 newDxc.osc = 0.0144;
3011 int nc = 10;
3012 newDxc.nChannels = nc;
3013 newDxc.p.resize(nc);
3014 newDxc.final.resize(nc);
3015 newDxc.type.resize(nc, DxcTypeRad);
3016 newDxc.p[0] = 4.21e-4;
3017 newDxc.final[0] = mapDxc["Ar_2P10"];
3018 newDxc.p[1] = 2.e-3;
3019 newDxc.final[1] = mapDxc["Ar_2P8"];
3020 newDxc.p[2] = 1.7e-3;
3021 newDxc.final[2] = mapDxc["Ar_2P7"];
3022 newDxc.p[3] = 7.2e-4;
3023 newDxc.final[3] = mapDxc["Ar_2P6"];
3024 newDxc.p[4] = 3.5e-4;
3025 newDxc.final[4] = mapDxc["Ar_2P5"];
3026 newDxc.p[5] = 1.2e-4;
3027 newDxc.final[5] = mapDxc["Ar_2P4"];
3028 newDxc.p[6] = 4.2e-6;
3029 newDxc.final[6] = mapDxc["Ar_2P3"];
3030 newDxc.p[7] = 3.3e-5;
3031 newDxc.final[7] = mapDxc["Ar_2P2"];
3032 newDxc.p[8] = 9.7e-5;
3033 newDxc.final[8] = mapDxc["Ar_2P1"];
3034 // Transition probability to ground state calculated from osc. strength
3035 newDxc.p[9] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3036 newDxc.final[9] = -1;
3037 } else if (level == "Ar_4D2") {
3038 // Oscillator strength from Berkowitz
3039 newDxc.osc = 0.048;
3040 int nc = 2;
3041 newDxc.nChannels = nc;
3042 newDxc.p.resize(nc);
3043 newDxc.final.resize(nc);
3044 newDxc.type.resize(nc, DxcTypeRad);
3045 newDxc.p[0] = 1.7e-4;
3046 newDxc.final[0] = mapDxc["Ar_2P7"];
3047 // Transition probability to ground state calculated from osc. strength
3048 newDxc.p[1] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3049 newDxc.final[1] = -1;
3050 } else if (level == "Ar_4S1!") {
3051 // Oscillator strength from Berkowitz
3052 newDxc.osc = 0.0209;
3053 int nc = 7;
3054 newDxc.nChannels = nc;
3055 newDxc.p.resize(nc);
3056 newDxc.final.resize(nc);
3057 newDxc.type.resize(nc, DxcTypeRad);
3058 newDxc.p[0] = 1.05e-3;
3059 newDxc.final[0] = mapDxc["Ar_2P10"];
3060 newDxc.p[1] = 3.1e-5;
3061 newDxc.final[1] = mapDxc["Ar_2P8"];
3062 newDxc.p[2] = 2.5e-5;
3063 newDxc.final[2] = mapDxc["Ar_2P7"];
3064 newDxc.p[3] = 4.0e-4;
3065 newDxc.final[3] = mapDxc["Ar_2P6"];
3066 newDxc.p[4] = 5.8e-5;
3067 newDxc.final[4] = mapDxc["Ar_2P5"];
3068 newDxc.p[5] = 1.2e-4;
3069 newDxc.final[5] = mapDxc["Ar_2P3"];
3070 // Transition probability to ground state calculated from osc. strength
3071 newDxc.p[6] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3072 newDxc.final[6] = -1;
3073 } else if (level == "Ar_3S2") {
3074 // Oscillator strength from Berkowitz
3075 newDxc.osc = 0.0221;
3076 int nc = 10;
3077 newDxc.nChannels = nc;
3078 newDxc.p.resize(nc);
3079 newDxc.final.resize(nc);
3080 newDxc.type.resize(nc, DxcTypeRad);
3081 newDxc.p[0] = 2.85e-4;
3082 newDxc.final[0] = mapDxc["Ar_2P10"];
3083 newDxc.p[1] = 5.1e-5;
3084 newDxc.final[1] = mapDxc["Ar_2P8"];
3085 newDxc.p[2] = 5.3e-5;
3086 newDxc.final[2] = mapDxc["Ar_2P7"];
3087 newDxc.p[3] = 1.6e-4;
3088 newDxc.final[3] = mapDxc["Ar_2P6"];
3089 newDxc.p[4] = 1.5e-4;
3090 newDxc.final[4] = mapDxc["Ar_2P5"];
3091 newDxc.p[5] = 6.0e-4;
3092 newDxc.final[5] = mapDxc["Ar_2P4"];
3093 newDxc.p[6] = 2.48e-3;
3094 newDxc.final[6] = mapDxc["Ar_2P3"];
3095 newDxc.p[7] = 9.6e-4;
3096 newDxc.final[7] = mapDxc["Ar_2P2"];
3097 newDxc.p[8] = 3.59e-4;
3098 newDxc.final[8] = mapDxc["Ar_2P1"];
3099 // Transition probability to ground state calculated from osc. strength
3100 newDxc.p[9] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3101 newDxc.final[9] = -1;
3102 } else if (level == "Ar_5D5") {
3103 // Oscillator strength from Berkowitz
3104 newDxc.osc = 0.0041;
3105 int nc = 9;
3106 newDxc.nChannels = nc;
3107 newDxc.p.resize(nc);
3108 newDxc.final.resize(nc);
3109 newDxc.type.resize(nc, DxcTypeRad);
3110 newDxc.p[0] = 2.2e-3;
3111 newDxc.final[0] = mapDxc["Ar_2P10"];
3112 newDxc.p[1] = 1.1e-4;
3113 newDxc.final[1] = mapDxc["Ar_2P8"];
3114 newDxc.p[2] = 7.6e-5;
3115 newDxc.final[2] = mapDxc["Ar_2P7"];
3116 newDxc.p[3] = 4.2e-4;
3117 newDxc.final[3] = mapDxc["Ar_2P6"];
3118 newDxc.p[4] = 2.4e-4;
3119 newDxc.final[4] = mapDxc["Ar_2P5"];
3120 newDxc.p[5] = 2.1e-4;
3121 newDxc.final[5] = mapDxc["Ar_2P4"];
3122 newDxc.p[6] = 2.4e-4;
3123 newDxc.final[6] = mapDxc["Ar_2P3"];
3124 newDxc.p[7] = 1.2e-4;
3125 newDxc.final[7] = mapDxc["Ar_2P2"];
3126 // Transition probability to ground state calculated from osc. strength
3127 newDxc.p[8] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3128 newDxc.final[8] = -1;
3129 } else if (level == "Ar_4S4") {
3130 // Oscillator strength from Berkowitz
3131 newDxc.osc = 0.0139;
3132 int nc = 7;
3133 newDxc.nChannels = nc;
3134 newDxc.p.resize(nc);
3135 newDxc.final.resize(nc);
3136 newDxc.type.resize(nc, DxcTypeRad);
3137 newDxc.p[0] = 1.9e-4;
3138 newDxc.final[0] = mapDxc["Ar_2P10"];
3139 newDxc.p[1] = 1.1e-3;
3140 newDxc.final[1] = mapDxc["Ar_2P8"];
3141 newDxc.p[2] = 5.2e-4;
3142 newDxc.final[2] = mapDxc["Ar_2P7"];
3143 newDxc.p[3] = 5.1e-4;
3144 newDxc.final[3] = mapDxc["Ar_2P6"];
3145 newDxc.p[4] = 9.4e-5;
3146 newDxc.final[4] = mapDxc["Ar_2P5"];
3147 newDxc.p[5] = 5.4e-5;
3148 newDxc.final[5] = mapDxc["Ar_2P4"];
3149 // Transition probability to ground state calculated from osc. strength
3150 newDxc.p[6] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3151 newDxc.final[6] = -1;
3152 } else if (level == "Ar_5D2") {
3153 // Oscillator strength from Berkowitz
3154 newDxc.osc = 0.0426;
3155 int nc = 5;
3156 newDxc.nChannels = nc;
3157 newDxc.p.resize(nc);
3158 newDxc.final.resize(nc);
3159 newDxc.type.resize(nc, DxcTypeRad);
3160 newDxc.p[0] = 5.9e-5;
3161 newDxc.final[0] = mapDxc["Ar_2P8"];
3162 newDxc.p[1] = 9.0e-6;
3163 newDxc.final[1] = mapDxc["Ar_2P7"];
3164 newDxc.p[2] = 1.5e-4;
3165 newDxc.final[2] = mapDxc["Ar_2P5"];
3166 newDxc.p[3] = 3.1e-5;
3167 newDxc.final[3] = mapDxc["Ar_2P2"];
3168 // Transition probability to ground state calculated from osc. strength
3169 newDxc.p[4] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3170 newDxc.final[4] = -1;
3171 } else if (level == "Ar_6D5") {
3172 // Oscillator strength from Lee and Lu
3173 newDxc.osc = 0.00075;
3174 // Berkowitz estimates f = 0.0062 for the sum of
3175 // all "weak" nd levels with n = 6 and higher.
3176 int nc = 7;
3177 newDxc.nChannels = nc;
3178 newDxc.p.resize(nc);
3179 newDxc.final.resize(nc);
3180 newDxc.type.resize(nc, DxcTypeRad);
3181 newDxc.p[0] = 1.9e-3;
3182 newDxc.final[0] = mapDxc["Ar_2P10"];
3183 newDxc.p[1] = 4.2e-4;
3184 newDxc.final[1] = mapDxc["Ar_2P6"];
3185 newDxc.p[2] = 3.e-4;
3186 newDxc.final[2] = mapDxc["Ar_2P5"];
3187 newDxc.p[3] = 5.1e-5;
3188 newDxc.final[3] = mapDxc["Ar_2P4"];
3189 newDxc.p[4] = 6.6e-5;
3190 newDxc.final[4] = mapDxc["Ar_2P3"];
3191 newDxc.p[5] = 1.21e-4;
3192 newDxc.final[5] = mapDxc["Ar_2P1"];
3193 // Transition probability to ground state calculated from osc. strength
3194 newDxc.p[6] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3195 newDxc.final[6] = -1;
3196 } else if (level == "Ar_5S1!") {
3197 // Oscillator strength from Lee and Lu
3198 newDxc.osc = 0.00051;
3199 // Berkowitz estimates f = 0.0562 for the sum
3200 // of all nd' levels with n = 5 and higher.
3201 int nc = 2;
3202 newDxc.nChannels = nc;
3203 newDxc.p.resize(nc);
3204 newDxc.final.resize(nc);
3205 newDxc.type.resize(nc, DxcTypeRad);
3206 newDxc.p[0] = 7.7e-5;
3207 newDxc.final[0] = mapDxc["Ar_2P5"];
3208 // Transition probability to ground state calculated from osc. strength
3209 newDxc.p[1] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3210 newDxc.final[1] = -1;
3211 } else if (level == "Ar_4S2") {
3212 // Oscillator strength from Lee and Lu
3213 newDxc.osc = 0.00074;
3214 // Berkowitz estimates f = 0.0069 for the sum over all
3215 // ns' levels with n = 7 and higher.
3216 int nc = 8;
3217 newDxc.nChannels = nc;
3218 newDxc.p.resize(nc);
3219 newDxc.final.resize(nc);
3220 newDxc.type.resize(nc, DxcTypeRad);
3221 newDxc.p[0] = 4.5e-4;
3222 newDxc.final[0] = mapDxc["Ar_2P10"];
3223 newDxc.p[1] = 2.e-4;
3224 newDxc.final[1] = mapDxc["Ar_2P8"];
3225 newDxc.p[2] = 2.1e-4;
3226 newDxc.final[2] = mapDxc["Ar_2P7"];
3227 newDxc.p[3] = 1.2e-4;
3228 newDxc.final[3] = mapDxc["Ar_2P5"];
3229 newDxc.p[4] = 1.8e-4;
3230 newDxc.final[4] = mapDxc["Ar_2P4"];
3231 newDxc.p[5] = 9.e-4;
3232 newDxc.final[5] = mapDxc["Ar_2P3"];
3233 newDxc.p[6] = 3.3e-4;
3234 newDxc.final[6] = mapDxc["Ar_2P2"];
3235 // Transition probability to ground state calculated from osc. strength
3236 newDxc.p[7] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3237 newDxc.final[7] = -1;
3238 } else if (level == "Ar_5S4") {
3239 // Oscillator strength from Lee and Lu
3240 newDxc.osc = 0.0130;
3241 // Berkowitz estimates f = 0.0211 for the sum of all
3242 // ns levels with n = 8 and higher.
3243 newDxc.osc = 0.0211;
3244 int nc = 6;
3245 newDxc.nChannels = nc;
3246 newDxc.p.resize(nc);
3247 newDxc.final.resize(nc);
3248 newDxc.type.resize(nc, DxcTypeRad);
3249 newDxc.p[0] = 3.6e-4;
3250 newDxc.final[0] = mapDxc["Ar_2P8"];
3251 newDxc.p[1] = 1.2e-4;
3252 newDxc.final[1] = mapDxc["Ar_2P6"];
3253 newDxc.p[2] = 1.5e-4;
3254 newDxc.final[2] = mapDxc["Ar_2P4"];
3255 newDxc.p[3] = 1.4e-4;
3256 newDxc.final[3] = mapDxc["Ar_2P3"];
3257 newDxc.p[4] = 7.5e-5;
3258 newDxc.final[4] = mapDxc["Ar_2P2"];
3259 // Transition probability to ground state calculated from osc. strength
3260 newDxc.p[5] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3261 newDxc.final[5] = -1;
3262 } else if (level == "Ar_6D2") {
3263 // Oscillator strength from Lee and Lu
3264 newDxc.osc = 0.0290;
3265 // Berkowitz estimates f = 0.0574 for the sum of all
3266 // "strong" nd levels with n = 6 and higher.
3267 newDxc.osc = 0.0574;
3268 int nc = 2;
3269 newDxc.nChannels = nc;
3270 newDxc.p.resize(nc);
3271 newDxc.final.resize(nc);
3272 newDxc.type.resize(nc, DxcTypeRad);
3273 // Additional line: 2P7
3274 newDxc.p[0] = 3.33e-3;
3275 newDxc.final[0] = mapDxc["Ar_2P7"];
3276 // Transition probability to ground state calculated from osc. strength
3277 newDxc.p[1] = f2A * pow(newDxc.energy, 2) * newDxc.osc;
3278 newDxc.final[1] = -1;
3279 } else if (level == "Ar_Higher") {
3280 newDxc.osc = 0.;
3281 // This (artificial) level represents the sum of higher J = 1 states.
3282 // The deeexcitation cascade is simulated by allocating it
3283 // with equal probability to one of the five nearest levels below.
3284 int nc = 5;
3285 newDxc.nChannels = nc;
3286 newDxc.p.resize(nc);
3287 newDxc.final.resize(nc);
3288 newDxc.type.resize(nc, DxcTypeCollNonIon);
3289 newDxc.p[0] = 100.;
3290 newDxc.final[0] = mapDxc["Ar_6D5"];
3291 newDxc.p[1] = 100.;
3292 newDxc.final[1] = mapDxc["Ar_5S1!"];
3293 newDxc.p[2] = 100.;
3294 newDxc.final[2] = mapDxc["Ar_4S2"];
3295 newDxc.p[3] = 100.;
3296 newDxc.final[3] = mapDxc["Ar_5S4"];
3297 newDxc.p[4] = 100.;
3298 newDxc.final[4] = mapDxc["Ar_6D2"];
3299 } else {
3300 std::cerr << m_className << "::ComputeDeexcitationTable:\n";
3301 std::cerr << " Missing de-excitation data for level " << level
3302 << ".\n";
3303 std::cerr << " Program bug!\n";
3304 return;
3305 }
3306 deexcitations.push_back(newDxc);
3307 }
3308
3309 if (m_debug || verbose) {
3310 std::cout << m_className << "::ComputeDeexcitationTable:\n";
3311 std::cout << " Found " << nDeexcitations << " levels "
3312 << "with available radiative de-excitation data.\n";
3313 }
3314
3315 // Collisional de-excitation channels
3316 if (withAr) {
3317 // Add the Ar dimer ground state.
3318 newDxc.label = "Ar_Dimer";
3319 newDxc.level = -1;
3320 newDxc.gas = iAr;
3321 newDxc.energy = 14.71;
3322 newDxc.osc = newDxc.cf = 0.;
3323 newDxc.sDoppler = newDxc.gPressure = newDxc.width = 0.;
3324 newDxc.p.clear();
3325 newDxc.final.clear();
3326 newDxc.type.clear();
3327 newDxc.nChannels = 0;
3328 mapDxc["Ar_Dimer"] = nDeexcitations;
3329 deexcitations.push_back(newDxc);
3330 ++nDeexcitations;
3331 // Add an Ar excimer level.
3332 newDxc.label = "Ar_Excimer";
3333 newDxc.level = -1;
3334 newDxc.gas = iAr;
3335 newDxc.energy = 14.71;
3336 newDxc.osc = newDxc.cf = 0.;
3337 newDxc.sDoppler = newDxc.gPressure = newDxc.width = 0.;
3338 newDxc.p.clear();
3339 newDxc.final.clear();
3340 newDxc.type.clear();
3341 newDxc.nChannels = 0;
3342 mapDxc["Ar_Excimer"] = nDeexcitations;
3343 deexcitations.push_back(newDxc);
3344 ++nDeexcitations;
3345 const double nAr = GetNumberDensity() * cAr;
3346 for (int j = nDeexcitations; j--;) {
3347 std::string level = deexcitations[j].label;
3348 if (level == "Ar_1S5") {
3349 // Two-body and three-body collision rate constants
3350 // Three-body collisions lead to excimer formation.
3351 // Two-body collisions give rise to collisional mixing.
3352 const bool useTachibanaData = false;
3353 const bool useKoltsSetserData = true;
3354 const bool useCollMixing = true;
3355 if (useTachibanaData) {
3356 // K. Tachibana, Phys. Rev. A 34 (1986), 1007-1015
3357 const double k2b = 2.3e-24;
3358 const double k3b = 1.4e-41;
3359 deexcitations[j].p.push_back(k3b * nAr * nAr);
3360 deexcitations[j].final.push_back(mapDxc["Ar_Excimer"]);
3361 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3362 deexcitations[j].nChannels += 1;
3363 if (useCollMixing) {
3364 deexcitations[j].p.push_back(k2b * nAr);
3365 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3366 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3367 deexcitations[j].nChannels += 1;
3368 }
3369 } else if (useKoltsSetserData) {
3370 // Kolts and Setser, J. Chem. Phys. 68 (1978), 4848-4859
3371 const double k2b = 2.1e-24;
3372 const double k3b = 1.1e-41;
3373 deexcitations[j].p.push_back(k3b * nAr * nAr);
3374 deexcitations[j].final.push_back(mapDxc["Ar_Excimer"]);
3375 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3376 deexcitations[j].nChannels += 1;
3377 if (useCollMixing) {
3378 deexcitations[j].p.push_back(k2b * nAr);
3379 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3380 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3381 deexcitations[j].nChannels += 1;
3382 }
3383 }
3384 }
3385 if (level == "Ar_1S3") {
3386 // Two-body and three-body collision rate constants
3387 const bool useTachibanaData = false;
3388 const bool useKoltsSetserData = true;
3389 const bool useCollMixing = true;
3390 if (useTachibanaData) {
3391 // K. Tachibana, Phys. Rev. A 34 (1986), 1007-1015
3392 const double k2b = 4.3e-24;
3393 const double k3b = 1.5e-41;
3394 deexcitations[j].p.push_back(k3b * nAr * nAr);
3395 deexcitations[j].final.push_back(mapDxc["Ar_Excimer"]);
3396 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3397 deexcitations[j].nChannels += 1;
3398 if (useCollMixing) {
3399 deexcitations[j].p.push_back(k2b * nAr);
3400 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3401 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3402 deexcitations[j].nChannels += 1;
3403 }
3404 } else if (useKoltsSetserData) {
3405 // Kolts and Setser, J. Chem. Phys. 68 (1978), 4848-4859
3406 const double k2b = 5.3e-24;
3407 const double k3b = 0.83e-41;
3408 deexcitations[j].p.push_back(k3b * nAr * nAr);
3409 deexcitations[j].final.push_back(mapDxc["Ar_Excimer"]);
3410 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3411 deexcitations[j].nChannels += 1;
3412 if (useCollMixing) {
3413 deexcitations[j].p.push_back(k2b * nAr);
3414 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3415 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3416 deexcitations[j].nChannels += 1;
3417 }
3418 }
3419 }
3420 if (level == "Ar_2P1") {
3421 // Transfer to 4s states
3422 // Inoue, Setser, and Sadeghi, J. Chem. Phys. 75 (1982), 977-983
3423 // const double k4s = 2.9e-20;
3424 // Sadeghi et al. J. Chem. Phys. 115 (2001), 3144-3154
3425 const double k4s = 1.6e-20;
3426 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3427 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3428 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3429 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3430 deexcitations[j].final.push_back(mapDxc["Ar_1S5"]);
3431 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3432 deexcitations[j].final.push_back(mapDxc["Ar_1S3"]);
3433 deexcitations[j].final.push_back(mapDxc["Ar_1S2"]);
3434 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3435 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3436 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3437 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3438 deexcitations[j].nChannels += 4;
3439 }
3440 if (level == "Ar_2P2") {
3441 // Collisional population transfer within 4p levels
3442 // T. D. Nguyen and N. Sadeghi, Phys. Rev. 18 (1978), 1388-1395
3443 const double k23 = 0.5e-21;
3444 deexcitations[j].p.push_back(k23 * nAr);
3445 deexcitations[j].final.push_back(mapDxc["Ar_2P3"]);
3446 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3447 deexcitations[j].nChannels += 1;
3448 // Transfer to 4s states
3449 // Inoue, Setser, and Sadeghi, J. Chem. Phys. 75 (1982), 977-983
3450 // const double k4s = 3.8e-20;
3451 // Chang and Setser, J. Chem. Phys. 69 (1978), 3885-3897
3452 const double k4s = 5.3e-20;
3453 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3454 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3455 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3456 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3457 deexcitations[j].final.push_back(mapDxc["Ar_1S5"]);
3458 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3459 deexcitations[j].final.push_back(mapDxc["Ar_1S3"]);
3460 deexcitations[j].final.push_back(mapDxc["Ar_1S2"]);
3461 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3462 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3463 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3464 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3465 deexcitations[j].nChannels += 4;
3466 }
3467 if (level == "Ar_2P3") {
3468 // Collisional population transfer within 4p levels
3469 // T. D. Nguyen and N. Sadeghi, Phys. Rev. 18 (1978), 1388-1395
3470 const double k34 = 27.5e-21;
3471 const double k35 = 0.3e-21;
3472 const double k36 = 44.0e-21;
3473 const double k37 = 1.4e-21;
3474 const double k38 = 1.9e-21;
3475 const double k39 = 0.8e-21;
3476 deexcitations[j].p.push_back(k34 * nAr);
3477 deexcitations[j].p.push_back(k35 * nAr);
3478 deexcitations[j].p.push_back(k36 * nAr);
3479 deexcitations[j].p.push_back(k37 * nAr);
3480 deexcitations[j].p.push_back(k38 * nAr);
3481 deexcitations[j].p.push_back(k39 * nAr);
3482 deexcitations[j].final.push_back(mapDxc["Ar_2P4"]);
3483 deexcitations[j].final.push_back(mapDxc["Ar_2P5"]);
3484 deexcitations[j].final.push_back(mapDxc["Ar_2P6"]);
3485 deexcitations[j].final.push_back(mapDxc["Ar_2P7"]);
3486 deexcitations[j].final.push_back(mapDxc["Ar_2P8"]);
3487 deexcitations[j].final.push_back(mapDxc["Ar_2P9"]);
3488 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3489 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3490 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3491 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3492 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3493 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3494 deexcitations[j].nChannels += 6;
3495 // Transfer to 4s states
3496 // Chang and Setser, J. Chem. Phys. 69 (1978), 3885-3897
3497 const double k4s = 4.7e-20;
3498 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3499 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3500 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3501 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3502 deexcitations[j].final.push_back(mapDxc["Ar_1S5"]);
3503 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3504 deexcitations[j].final.push_back(mapDxc["Ar_1S3"]);
3505 deexcitations[j].final.push_back(mapDxc["Ar_1S2"]);
3506 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3507 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3508 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3509 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3510 deexcitations[j].nChannels += 4;
3511 }
3512 if (level == "Ar_2P4") {
3513 // Collisional population transfer within 4p levels
3514 // T. D. Nguyen and N. Sadeghi, Phys. Rev. 18 (1978), 1388-1395
3515 const double k43 = 23.0e-21;
3516 const double k45 = 0.7e-21;
3517 const double k46 = 4.8e-21;
3518 const double k47 = 3.2e-21;
3519 const double k48 = 1.4e-21;
3520 const double k49 = 3.3e-21;
3521 deexcitations[j].p.push_back(k43 * nAr);
3522 deexcitations[j].p.push_back(k45 * nAr);
3523 deexcitations[j].p.push_back(k46 * nAr);
3524 deexcitations[j].p.push_back(k47 * nAr);
3525 deexcitations[j].p.push_back(k48 * nAr);
3526 deexcitations[j].p.push_back(k49 * nAr);
3527 deexcitations[j].final.push_back(mapDxc["Ar_2P3"]);
3528 deexcitations[j].final.push_back(mapDxc["Ar_2P5"]);
3529 deexcitations[j].final.push_back(mapDxc["Ar_2P6"]);
3530 deexcitations[j].final.push_back(mapDxc["Ar_2P7"]);
3531 deexcitations[j].final.push_back(mapDxc["Ar_2P8"]);
3532 deexcitations[j].final.push_back(mapDxc["Ar_2P9"]);
3533 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3534 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3535 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3536 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3537 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3538 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3539 deexcitations[j].nChannels += 6;
3540 // Transfer to 4s states
3541 // Chang and Setser, J. Chem. Phys. 69 (1978), 3885-3897
3542 const double k4s = 3.9e-20;
3543 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3544 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3545 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3546 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3547 deexcitations[j].final.push_back(mapDxc["Ar_1S5"]);
3548 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3549 deexcitations[j].final.push_back(mapDxc["Ar_1S3"]);
3550 deexcitations[j].final.push_back(mapDxc["Ar_1S2"]);
3551 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3552 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3553 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3554 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3555 deexcitations[j].nChannels += 4;
3556 }
3557 if (level == "Ar_2P5") {
3558 // Collisional population transfer within 4p levels
3559 // T. D. Nguyen and N. Sadeghi, Phys. Rev. 18 (1978), 1388-1395
3560 const double k54 = 1.7e-21;
3561 const double k56 = 11.3e-21;
3562 const double k58 = 9.5e-21;
3563 deexcitations[j].p.push_back(k54 * nAr);
3564 deexcitations[j].p.push_back(k56 * nAr);
3565 deexcitations[j].p.push_back(k58 * nAr);
3566 deexcitations[j].final.push_back(mapDxc["Ar_2P4"]);
3567 deexcitations[j].final.push_back(mapDxc["Ar_2P6"]);
3568 deexcitations[j].final.push_back(mapDxc["Ar_2P8"]);
3569 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3570 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3571 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3572 deexcitations[j].nChannels += 3;
3573 }
3574 if (level == "Ar_2P6") {
3575 // Collisional population transfer within 4p levels
3576 // T. D. Nguyen and N. Sadeghi, Phys. Rev. 18 (1978), 1388-1395
3577 const double k67 = 4.1e-21;
3578 const double k68 = 6.0e-21;
3579 const double k69 = 1.0e-21;
3580 deexcitations[j].p.push_back(k67 * nAr);
3581 deexcitations[j].p.push_back(k68 * nAr);
3582 deexcitations[j].p.push_back(k69 * nAr);
3583 deexcitations[j].final.push_back(mapDxc["Ar_2P7"]);
3584 deexcitations[j].final.push_back(mapDxc["Ar_2P8"]);
3585 deexcitations[j].final.push_back(mapDxc["Ar_2P9"]);
3586 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3587 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3588 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3589 deexcitations[j].nChannels += 3;
3590 }
3591 if (level == "Ar_2P7") {
3592 // Collisional population transfer within 4p levels
3593 // T. D. Nguyen and N. Sadeghi, Phys. Rev. 18 (1978), 1388-1395
3594 const double k76 = 2.5e-21;
3595 const double k78 = 14.3e-21;
3596 const double k79 = 23.3e-21;
3597 deexcitations[j].p.push_back(k76 * nAr);
3598 deexcitations[j].p.push_back(k78 * nAr);
3599 deexcitations[j].p.push_back(k79 * nAr);
3600 deexcitations[j].final.push_back(mapDxc["Ar_2P6"]);
3601 deexcitations[j].final.push_back(mapDxc["Ar_2P8"]);
3602 deexcitations[j].final.push_back(mapDxc["Ar_2P9"]);
3603 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3604 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3605 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3606 deexcitations[j].nChannels += 3;
3607 // Transfer to 4s states
3608 // Chang and Setser, J. Chem. Phys. 69 (1978), 3885-3897
3609 const double k4s = 5.5e-20;
3610 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3611 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3612 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3613 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3614 deexcitations[j].final.push_back(mapDxc["Ar_1S5"]);
3615 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3616 deexcitations[j].final.push_back(mapDxc["Ar_1S3"]);
3617 deexcitations[j].final.push_back(mapDxc["Ar_1S2"]);
3618 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3619 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3620 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3621 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3622 deexcitations[j].nChannels += 4;
3623 }
3624 if (level == "Ar_2P8") {
3625 // Collisional population transfer within 4p levels
3626 // T. D. Nguyen and N. Sadeghi, Phys. Rev. 18 (1978), 1388-1395
3627 const double k86 = 0.3e-21;
3628 const double k87 = 0.8e-21;
3629 const double k89 = 18.2e-21;
3630 const double k810 = 1.0e-21;
3631 deexcitations[j].p.push_back(k86 * nAr);
3632 deexcitations[j].p.push_back(k87 * nAr);
3633 deexcitations[j].p.push_back(k89 * nAr);
3634 deexcitations[j].p.push_back(k810 * nAr);
3635 deexcitations[j].final.push_back(mapDxc["Ar_2P6"]);
3636 deexcitations[j].final.push_back(mapDxc["Ar_2P7"]);
3637 deexcitations[j].final.push_back(mapDxc["Ar_2P9"]);
3638 deexcitations[j].final.push_back(mapDxc["Ar_2P10"]);
3639 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3640 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3641 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3642 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3643 deexcitations[j].nChannels += 4;
3644 // Transfer to 4s states
3645 // Chang and Setser, J. Chem. Phys. 69 (1978), 3885-3897
3646 const double k4s = 3.e-20;
3647 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3648 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3649 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3650 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3651 deexcitations[j].final.push_back(mapDxc["Ar_1S5"]);
3652 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3653 deexcitations[j].final.push_back(mapDxc["Ar_1S3"]);
3654 deexcitations[j].final.push_back(mapDxc["Ar_1S2"]);
3655 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3656 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3657 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3658 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3659 deexcitations[j].nChannels += 4;
3660 }
3661 if (level == "Ar_2P9") {
3662 // Collisional population transfer within 4p levels
3663 // T. D. Nguyen and N. Sadeghi, Phys. Rev. 18 (1978), 1388-1395
3664 const double k98 = 6.8e-21;
3665 const double k910 = 5.1e-21;
3666 deexcitations[j].p.push_back(k98 * nAr);
3667 deexcitations[j].p.push_back(k910 * nAr);
3668 deexcitations[j].final.push_back(mapDxc["Ar_2P8"]);
3669 deexcitations[j].final.push_back(mapDxc["Ar_2P10"]);
3670 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3671 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3672 deexcitations[j].nChannels += 2;
3673 // Transfer to 4s states
3674 // Chang and Setser, J. Chem. Phys. 69 (1978), 3885-3897
3675 const double k4s = 3.5e-20;
3676 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3677 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3678 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3679 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3680 deexcitations[j].final.push_back(mapDxc["Ar_1S5"]);
3681 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3682 deexcitations[j].final.push_back(mapDxc["Ar_1S3"]);
3683 deexcitations[j].final.push_back(mapDxc["Ar_1S2"]);
3684 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3685 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3686 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3687 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3688 deexcitations[j].nChannels += 4;
3689 }
3690 if (level == "Ar_2P10") {
3691 // Transfer to 4s states
3692 // Chang and Setser, J. Chem. Phys. 69 (1978), 3885-3897
3693 const double k4s = 2.0e-20;
3694 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3695 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3696 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3697 deexcitations[j].p.push_back(0.25 * k4s * nAr);
3698 deexcitations[j].final.push_back(mapDxc["Ar_1S5"]);
3699 deexcitations[j].final.push_back(mapDxc["Ar_1S4"]);
3700 deexcitations[j].final.push_back(mapDxc["Ar_1S3"]);
3701 deexcitations[j].final.push_back(mapDxc["Ar_1S2"]);
3702 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3703 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3704 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3705 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3706 deexcitations[j].nChannels += 4;
3707 }
3708 if (level == "Ar_3D6" || level == "Ar_3D5" || level == "Ar_3D3" ||
3709 level == "Ar_3D4!" || level == "Ar_3D4" || level == "Ar_3D1!!" ||
3710 level == "Ar_3D1!" || level == "Ar_3D2" || level == "Ar_3S1!!!!" ||
3711 level == "Ar_3S1!!" || level == "Ar_3S1!!!" || level == "Ar_3S1!" ||
3712 level == "Ar_2S5" || level == "Ar_2S4" || level == "Ar_2S3" ||
3713 level == "Ar_2S2") {
3714 // 3d and 5s levels
3715 // Transfer to 4p levels
3716 const double k4p = fit3d4p * 1.e-20;
3717 deexcitations[j].final.push_back(mapDxc["Ar_2P10"]);
3718 deexcitations[j].final.push_back(mapDxc["Ar_2P9"]);
3719 deexcitations[j].final.push_back(mapDxc["Ar_2P8"]);
3720 deexcitations[j].final.push_back(mapDxc["Ar_2P7"]);
3721 deexcitations[j].final.push_back(mapDxc["Ar_2P6"]);
3722 deexcitations[j].final.push_back(mapDxc["Ar_2P5"]);
3723 deexcitations[j].final.push_back(mapDxc["Ar_2P4"]);
3724 deexcitations[j].final.push_back(mapDxc["Ar_2P3"]);
3725 deexcitations[j].final.push_back(mapDxc["Ar_2P2"]);
3726 deexcitations[j].final.push_back(mapDxc["Ar_2P1"]);
3727 for (int k = 10; k--;) {
3728 deexcitations[j].p.push_back(0.1 * k4p * nAr);
3729 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3730 }
3731 deexcitations[j].nChannels += 10;
3732 }
3733 if (level == "Ar_4D5" || level == "Ar_3S4" || level == "Ar_4D2" ||
3734 level == "Ar_4S1!" || level == "Ar_3S2" || level == "Ar_5D5" ||
3735 level == "Ar_4S4" || level == "Ar_5D2" || level == "Ar_6D5" ||
3736 level == "Ar_5S1!" || level == "Ar_4S2" || level == "Ar_5S4" ||
3737 level == "Ar_6D2") {
3738 // Transfer to 4p levels
3739 const double k4p = fitHigh4p * 1.e-20;
3740 deexcitations[j].final.push_back(mapDxc["Ar_2P10"]);
3741 deexcitations[j].final.push_back(mapDxc["Ar_2P9"]);
3742 deexcitations[j].final.push_back(mapDxc["Ar_2P8"]);
3743 deexcitations[j].final.push_back(mapDxc["Ar_2P7"]);
3744 deexcitations[j].final.push_back(mapDxc["Ar_2P6"]);
3745 deexcitations[j].final.push_back(mapDxc["Ar_2P5"]);
3746 deexcitations[j].final.push_back(mapDxc["Ar_2P4"]);
3747 deexcitations[j].final.push_back(mapDxc["Ar_2P3"]);
3748 deexcitations[j].final.push_back(mapDxc["Ar_2P2"]);
3749 deexcitations[j].final.push_back(mapDxc["Ar_2P1"]);
3750 for (int k = 10; k--;) {
3751 deexcitations[j].p.push_back(0.1 * k4p * nAr);
3752 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3753 }
3754 deexcitations[j].nChannels += 10;
3755 // Hornbeck-Molnar ionisation
3756 // P. Becker and F. Lampe, J. Chem. Phys. 42 (1965), 3857-3863
3757 // A. Bogaerts and R. Gijbels, Phys. Rev. A 52 (1995), 3743-3751
3758 // This value seems high, to be checked!
3759 const double kHM = 2.e-18;
3760 const bool useHornbeckMolnar = true;
3761 if (useHornbeckMolnar) {
3762 deexcitations[j].p.push_back(kHM * nAr);
3763 deexcitations[j].final.push_back(mapDxc["Ar_Dimer"]);
3764 deexcitations[j].type.push_back(DxcTypeCollIon);
3765 deexcitations[j].nChannels += 1;
3766 }
3767 }
3768 }
3769 }
3770
3771 // Collisional deexcitation by quenching gases.
3772 bool withCO2 = false;
3773 double cCO2 = 0.;
3774 int iCO2 = 0;
3775 bool withCH4 = false;
3776 double cCH4 = 0.;
3777 int iCH4 = 0;
3778 bool withC2H6 = false;
3779 double cC2H6 = 0.;
3780 int iC2H6 = 0;
3781 bool withIso = false;
3782 double cIso = 0.;
3783 int iIso = 0;
3784 bool withC2H2 = false;
3785 double cC2H2 = 0.;
3786 int iC2H2 = 0;
3787 bool withCF4 = false;
3788 double cCF4 = 0.;
3789 int iCF4 = 0;
3790 for (unsigned int i = 0; i < m_nComponents; ++i) {
3791 if (gas[i] == "CO2") {
3792 withCO2 = true;
3793 cCO2 = fraction[i];
3794 iCO2 = i;
3795 } else if (gas[i] == "CH4") {
3796 withCH4 = true;
3797 cCH4 = fraction[i];
3798 iCH4 = i;
3799 } else if (gas[i] == "C2H6") {
3800 withC2H6 = true;
3801 cC2H6 = fraction[i];
3802 iC2H6 = i;
3803 } else if (gas[i] == "C2H2") {
3804 withC2H2 = true;
3805 cC2H2 = fraction[i];
3806 iC2H2 = i;
3807 } else if (gas[i] == "CF4") {
3808 withCF4 = true;
3809 cCF4 = fraction[i];
3810 iCF4 = i;
3811 } else if (gas[i] == "iC4H10") {
3812 withIso = true;
3813 cIso = fraction[i];
3814 iIso = i;
3815 }
3816 }
3817
3818 if (withAr && withCO2) {
3819 // Partial density of CO2
3820 const double nQ = GetNumberDensity() * cCO2;
3821 for (int j = nDeexcitations; j--;) {
3822 std::string level = deexcitations[j].label;
3823 // Photoabsorption cross-section and ionisation yield
3824 double pacs = 0., eta = 0.;
3825 if (!optData.GetPhotoabsorptionCrossSection(
3826 "CO2", deexcitations[j].energy, pacs, eta)) {
3827 pacs = eta = 0.;
3828 }
3829 const double pPenningWK = pow(eta, 2. / 5.);
3830 if (level == "Ar_1S5") {
3831 // Rate constant from Velazco et al., J. Chem. Phys. 69 (1978)
3832 const double kQ = 5.3e-19;
3833 deexcitations[j].p.push_back(kQ * nQ);
3834 deexcitations[j].final.push_back(-1);
3835 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3836 deexcitations[j].nChannels += 1;
3837 } else if (level == "Ar_1S4") {
3838 // Rate constant from Velazco et al., J. Chem. Phys. 69 (1978)
3839 const double kQ = 5.0e-19;
3840 deexcitations[j].p.push_back(kQ * nQ);
3841 deexcitations[j].final.push_back(-1);
3842 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3843 deexcitations[j].nChannels += 1;
3844 } else if (level == "Ar_1S3") {
3845 const double kQ = 5.9e-19;
3846 deexcitations[j].p.push_back(kQ * nQ);
3847 deexcitations[j].final.push_back(-1);
3848 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3849 deexcitations[j].nChannels += 1;
3850 } else if (level == "Ar_1S2") {
3851 const double kQ = 7.4e-19;
3852 deexcitations[j].p.push_back(kQ * nQ);
3853 deexcitations[j].final.push_back(-1);
3854 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3855 deexcitations[j].nChannels += 1;
3856 } else if (level == "Ar_2P8") {
3857 // Rate constant from Sadeghi et al., J. Chem. Phys. 115 (2001)
3858 const double kQ = 6.4e-19;
3859 deexcitations[j].p.push_back(kQ * nQ);
3860 deexcitations[j].final.push_back(-1);
3861 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3862 deexcitations[j].nChannels += 1;
3863 } else if (level == "Ar_2P6") {
3864 // Rate constant from Sadeghi et al.
3865 const double kQ = 6.1e-19;
3866 deexcitations[j].p.push_back(kQ * nQ);
3867 deexcitations[j].final.push_back(-1);
3868 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3869 deexcitations[j].nChannels += 1;
3870 } else if (level == "Ar_2P5") {
3871 // Rate constant from Sadeghi et al.
3872 const double kQ = 6.6e-19;
3873 deexcitations[j].p.push_back(kQ * nQ);
3874 deexcitations[j].final.push_back(-1);
3875 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3876 deexcitations[j].nChannels += 1;
3877 } else if (level == "Ar_2P1") {
3878 // Rate constant from Sadeghi et al.
3879 const double kQ = 6.2e-19;
3880 deexcitations[j].p.push_back(kQ * nQ);
3881 deexcitations[j].final.push_back(-1);
3882 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3883 deexcitations[j].nChannels += 1;
3884 } else if (level == "Ar_2P10" || level == "Ar_2P9" || level == "Ar_2P7" ||
3885 level == "Ar_2P4" || level == "Ar_2P3" || level == "Ar_2P2") {
3886 // Average of 4p rate constants from Sadeghi et al.
3887 const double kQ = 6.33e-19;
3888 deexcitations[j].p.push_back(kQ * nQ);
3889 deexcitations[j].final.push_back(-1);
3890 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3891 deexcitations[j].nChannels += 1;
3892 } else if (deexcitations[j].osc > 0.) {
3893 // Higher resonance levels
3894 // Calculate rate constant from Watanabe-Katsuura formula.
3895 const double m1 = ElectronMassGramme / (rgas[iAr] - 1.);
3896 const double m2 = ElectronMassGramme / (rgas[iCO2] - 1.);
3897 // Compute the reduced mass.
3898 double mR = m1 * m2 / (m1 + m2);
3899 mR /= AtomicMassUnit;
3900 const double uA =
3901 (RydbergEnergy / deexcitations[j].energy) * deexcitations[j].osc;
3902 const double uQ =
3903 (2 * RydbergEnergy / deexcitations[j].energy) * pacs /
3904 (4 * Pi2 * FineStructureConstant * BohrRadius * BohrRadius);
3905 const double kQ =
3906 2.591e-19 * pow(uA * uQ, 2. / 5.) * pow(m_temperature / mR, 3. / 10.);
3907 if (m_debug) {
3908 std::cout << m_className << "::ComputeDeexcitationTable:\n";
3909 std::cout << " Rate constant for coll. deexcitation of\n"
3910 << " " << level << " by CO2 (W-K formula):\n"
3911 << " " << kQ << " cm3 ns-1\n";
3912 }
3913 double pPenning = pPenningWK;
3914 deexcitations[j].p.push_back(kQ * nQ * pPenning);
3915 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
3916 deexcitations[j].final.push_back(-1);
3917 deexcitations[j].final.push_back(-1);
3918 deexcitations[j].type.push_back(DxcTypeCollIon);
3919 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3920 deexcitations[j].nChannels += 2;
3921 } else if (level == "Ar_3D6" || level == "Ar_3D3" || level == "Ar_3D4!" ||
3922 level == "Ar_3D4" || level == "Ar_3D1!!" ||
3923 level == "Ar_3D1!" || level == "Ar_3S1!!!!" ||
3924 level == "Ar_3S1!!" || level == "Ar_3S1!!!") {
3925 // Non-resonant 3d levels
3926 // Collision radii
3927 const double rAr3d = 436.e-10;
3928 const double rCO2 = 165.e-10;
3929 // Hard sphere cross-section
3930 const double sigma = pow(rAr3d + rCO2, 2) * Pi;
3931 // Reduced mass
3932 const double m1 = ElectronMass / (rgas[iAr] - 1.);
3933 const double m2 = ElectronMass / (rgas[iCO2] - 1.);
3934 const double mR = m1 * m2 / (m1 + m2);
3935 // Relative velocity
3936 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
3937 m_temperature / (Pi * mR));
3938 const double kQ = fit3dQCO2 * sigma * vel;
3939 if (m_debug) {
3940 std::cout << m_className << "::ComputeDeexcitationTable:\n";
3941 std::cout << " Rate constant for coll. deexcitation of\n"
3942 << " " << level << " by CO2 (hard sphere):\n"
3943 << " " << kQ << " cm3 ns-1\n";
3944 }
3945 double pPenning = fit3dEtaCO2;
3946 deexcitations[j].p.push_back(kQ * nQ * pPenning);
3947 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
3948 deexcitations[j].final.push_back(-1);
3949 deexcitations[j].final.push_back(-1);
3950 deexcitations[j].type.push_back(DxcTypeCollIon);
3951 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3952 deexcitations[j].nChannels += 2;
3953 } else if (level == "Ar_2S5" || level == "Ar_2S3") {
3954 // Non-resonant 5s levels
3955 // Collision radii
3956 const double rAr5s = 635.e-10;
3957 const double rCO2 = 165.e-10;
3958 // Hard sphere cross-section
3959 const double sigma = pow(rAr5s + rCO2, 2) * Pi;
3960 // Reduced mass
3961 const double m1 = ElectronMass / (rgas[iAr] - 1.);
3962 const double m2 = ElectronMass / (rgas[iCO2] - 1.);
3963 const double mR = m1 * m2 / (m1 + m2);
3964 // Relative velocity
3965 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
3966 m_temperature / (Pi * mR));
3967 const double kQ = fit3dQCO2 * sigma * vel;
3968 if (m_debug) {
3969 std::cout << m_className << "::ComputeDeexcitationTable:\n";
3970 std::cout << " Rate constant for coll. deexcitation of\n"
3971 << " " << level << " by CO2 (hard sphere):\n"
3972 << " " << kQ << " cm3 ns-1\n";
3973 }
3974 double pPenning = fit3dEtaCO2;
3975 deexcitations[j].p.push_back(kQ * nQ * pPenning);
3976 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
3977 deexcitations[j].final.push_back(-1);
3978 deexcitations[j].final.push_back(-1);
3979 deexcitations[j].type.push_back(DxcTypeCollIon);
3980 deexcitations[j].type.push_back(DxcTypeCollNonIon);
3981 deexcitations[j].nChannels += 2;
3982 }
3983 }
3984 }
3985 if (withAr && withCH4) {
3986 // Partial density of methane
3987 const double nQ = GetNumberDensity() * cCH4;
3988 for (int j = nDeexcitations; j--;) {
3989 std::string level = deexcitations[j].label;
3990 // Photoabsorption cross-section and ionisation yield
3991 double pacs = 0., eta = 0.;
3992 if (!optData.GetPhotoabsorptionCrossSection(
3993 "CH4", deexcitations[j].energy, pacs, eta)) {
3994 pacs = eta = 0.;
3995 }
3996 const double pPenningWK = pow(eta, 2. / 5.);
3997 if (level == "Ar_1S5") {
3998 // Rate constant from Chen and Setser, J. Phys. Chem. 95 (1991)
3999 const double kQ = 4.55e-19;
4000 deexcitations[j].p.push_back(kQ * nQ);
4001 deexcitations[j].final.push_back(-1);
4002 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4003 deexcitations[j].nChannels += 1;
4004 } else if (level == "Ar_1S4") {
4005 // Rate constant from Velazco et al., J. Chem. Phys. 69 (1978)
4006 const double kQ = 4.5e-19;
4007 deexcitations[j].p.push_back(kQ * nQ);
4008 deexcitations[j].final.push_back(-1);
4009 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4010 deexcitations[j].nChannels += 1;
4011 } else if (level == "Ar_1S3") {
4012 // Rate constant from Chen and Setser
4013 const double kQ = 5.30e-19;
4014 deexcitations[j].p.push_back(kQ * nQ);
4015 deexcitations[j].final.push_back(-1);
4016 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4017 deexcitations[j].nChannels += 1;
4018 } else if (level == "Ar_1S2") {
4019 // Rate constant from Velazco et al.
4020 const double kQ = 5.7e-19;
4021 deexcitations[j].p.push_back(kQ * nQ);
4022 deexcitations[j].final.push_back(-1);
4023 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4024 deexcitations[j].nChannels += 1;
4025 } else if (level == "Ar_2P8") {
4026 // Rate constant from Sadeghi et al., J. Chem. Phys. 115 (2001)
4027 const double kQ = 7.4e-19;
4028 double pPenning = pPenningWK;
4029 if (pPenning > 0.) pPenning = fit4pEtaCH4;
4030 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4031 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4032 deexcitations[j].final.push_back(-1);
4033 deexcitations[j].final.push_back(-1);
4034 deexcitations[j].type.push_back(DxcTypeCollIon);
4035 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4036 deexcitations[j].nChannels += 2;
4037 } else if (level == "Ar_2P6") {
4038 // Rate constant from Sadeghi et al.
4039 const double kQ = 3.4e-19;
4040 double pPenning = pPenningWK;
4041 if (pPenning > 0.) pPenning = fit4pEtaCH4;
4042 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4043 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4044 deexcitations[j].final.push_back(-1);
4045 deexcitations[j].final.push_back(-1);
4046 deexcitations[j].type.push_back(DxcTypeCollIon);
4047 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4048 deexcitations[j].nChannels += 2;
4049 } else if (level == "Ar_2P5") {
4050 // Rate constant from Sadeghi et al.
4051 const double kQ = 6.0e-19;
4052 double pPenning = pPenningWK;
4053 if (pPenning > 0.) pPenning = fit4pEtaCH4;
4054 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4055 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4056 deexcitations[j].final.push_back(-1);
4057 deexcitations[j].final.push_back(-1);
4058 deexcitations[j].type.push_back(DxcTypeCollIon);
4059 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4060 deexcitations[j].nChannels += 2;
4061 } else if (level == "Ar_2P1") {
4062 // Rate constant from Sadeghi et al.
4063 const double kQ = 9.3e-19;
4064 double pPenning = pPenningWK;
4065 if (pPenning > 0.) pPenning = fit4pEtaCH4;
4066 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4067 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4068 deexcitations[j].final.push_back(-1);
4069 deexcitations[j].final.push_back(-1);
4070 deexcitations[j].type.push_back(DxcTypeCollIon);
4071 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4072 deexcitations[j].nChannels += 2;
4073 } else if (level == "Ar_2P10" || level == "Ar_2P9" || level == "Ar_2P7" ||
4074 level == "Ar_2P4" || level == "Ar_2P3" || level == "Ar_2P2") {
4075 // Average of rate constants given by Sadeghi et al.
4076 const double kQ = 6.53e-19;
4077 double pPenning = pPenningWK;
4078 if (pPenning > 0.) pPenning = fit4pEtaCH4;
4079 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4080 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4081 deexcitations[j].final.push_back(-1);
4082 deexcitations[j].final.push_back(-1);
4083 deexcitations[j].type.push_back(DxcTypeCollIon);
4084 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4085 deexcitations[j].nChannels += 2;
4086 } else if (deexcitations[j].osc > 0.) {
4087 // Higher resonance levels
4088 // Calculate rate constant from Watanabe-Katsuura formula.
4089 const double m1 = ElectronMassGramme / (rgas[iAr] - 1.);
4090 const double m2 = ElectronMassGramme / (rgas[iCH4] - 1.);
4091 // Compute the reduced mass.
4092 double mR = m1 * m2 / (m1 + m2);
4093 mR /= AtomicMassUnit;
4094 const double uA =
4095 (RydbergEnergy / deexcitations[j].energy) * deexcitations[j].osc;
4096 const double uQ =
4097 (2 * RydbergEnergy / deexcitations[j].energy) * pacs /
4098 (4 * Pi2 * FineStructureConstant * BohrRadius * BohrRadius);
4099 const double kQ =
4100 2.591e-19 * pow(uA * uQ, 2. / 5.) * pow(m_temperature / mR, 3. / 10.);
4101 if (m_debug) {
4102 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4103 std::cout << " Rate constant for coll. deexcitation of\n"
4104 << " " << level << " by CH4 (W-K formula):\n"
4105 << " " << kQ << " cm3 ns-1\n";
4106 }
4107 double pPenning = pPenningWK;
4108 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4109 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4110 deexcitations[j].final.push_back(-1);
4111 deexcitations[j].final.push_back(-1);
4112 deexcitations[j].type.push_back(DxcTypeCollIon);
4113 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4114 deexcitations[j].nChannels += 2;
4115 } else if (level == "Ar_3D6" || level == "Ar_3D3" || level == "Ar_3D4!" ||
4116 level == "Ar_3D4" || level == "Ar_3D1!!" ||
4117 level == "Ar_3D1!" || level == "Ar_3S1!!!!" ||
4118 level == "Ar_3S1!!" || level == "Ar_3S1!!!") {
4119 // Non-resonant 3d levels
4120 // Collision radii
4121 const double rAr3d = 436.e-10;
4122 const double rCH4 = 190.e-10;
4123 // Hard sphere cross-section
4124 const double sigma = pow(rAr3d + rCH4, 2) * Pi;
4125 // Reduced mass
4126 const double m1 = ElectronMass / (rgas[iAr] - 1.);
4127 const double m2 = ElectronMass / (rgas[iCH4] - 1.);
4128 const double mR = m1 * m2 / (m1 + m2);
4129 // Relative velocity
4130 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
4131 m_temperature / (Pi * mR));
4132 const double kQ = fit3dQCH4 * sigma * vel;
4133 if (m_debug) {
4134 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4135 std::cout << " Rate constant for coll. deexcitation of\n"
4136 << " " << level << " by CH4 (hard sphere):\n"
4137 << " " << kQ << " cm3 ns-1\n";
4138 }
4139 double pPenning = fit3dEtaCH4;
4140 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4141 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4142 deexcitations[j].final.push_back(-1);
4143 deexcitations[j].final.push_back(-1);
4144 deexcitations[j].type.push_back(DxcTypeCollIon);
4145 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4146 deexcitations[j].nChannels += 2;
4147 } else if (level == "Ar_2S5" || level == "Ar_2S3") {
4148 // Non-resonant 5s levels
4149 // Collision radii
4150 const double rAr5s = 635.e-10;
4151 const double rCH4 = 190.e-10;
4152 // Hard sphere cross-section
4153 const double sigma = pow(rAr5s + rCH4, 2) * Pi;
4154 // Reduced mass
4155 const double m1 = ElectronMass / (rgas[iAr] - 1.);
4156 const double m2 = ElectronMass / (rgas[iCH4] - 1.);
4157 const double mR = m1 * m2 / (m1 + m2);
4158 // Relative velocity
4159 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
4160 m_temperature / (Pi * mR));
4161 const double kQ = fit3dQCH4 * sigma * vel;
4162 if (m_debug) {
4163 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4164 std::cout << " Rate constant for coll. deexcitation of\n"
4165 << " " << level << " by CH4 (hard sphere):\n"
4166 << " " << kQ << " cm3 ns-1\n";
4167 }
4168 double pPenning = fit3dEtaCH4;
4169 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4170 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4171 deexcitations[j].final.push_back(-1);
4172 deexcitations[j].final.push_back(-1);
4173 deexcitations[j].type.push_back(DxcTypeCollIon);
4174 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4175 deexcitations[j].nChannels += 2;
4176 }
4177 }
4178 }
4179 if (withAr && withC2H6) {
4180 // Partial density of ethane
4181 const double nQ = GetNumberDensity() * cC2H6;
4182 for (int j = nDeexcitations; j--;) {
4183 std::string level = deexcitations[j].label;
4184 // Photoabsorption cross-section and ionisation yield
4185 double pacs = 0., eta = 0.;
4186 if (!optData.GetPhotoabsorptionCrossSection(
4187 "C2H6", deexcitations[j].energy, pacs, eta)) {
4188 pacs = eta = 0.;
4189 }
4190 const double pPenningWK = pow(eta, 2. / 5.);
4191 if (level == "Ar_1S5") {
4192 // Rate constant from Chen and Setser, J. Phys. Chem. 95 (1991)
4193 const double kQ = 5.29e-19;
4194 const double pPenning = pPenningWK;
4195 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4196 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4197 deexcitations[j].final.push_back(-1);
4198 deexcitations[j].final.push_back(-1);
4199 deexcitations[j].type.push_back(DxcTypeCollIon);
4200 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4201 deexcitations[j].nChannels += 2;
4202 } else if (level == "Ar_1S4") {
4203 // Rate constant from Velazco et al., J. Chem. Phys. 69 (1978)
4204 const double kQ = 6.2e-19;
4205 const double pPenning = pPenningWK;
4206 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4207 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4208 deexcitations[j].final.push_back(-1);
4209 deexcitations[j].final.push_back(-1);
4210 deexcitations[j].type.push_back(DxcTypeCollIon);
4211 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4212 deexcitations[j].nChannels += 2;
4213 } else if (level == "Ar_1S3") {
4214 // Rate constant from Chen and Setser
4215 const double kQ = 6.53e-19;
4216 const double pPenning = fit4sEtaC2H6;
4217 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4218 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4219 deexcitations[j].final.push_back(-1);
4220 deexcitations[j].final.push_back(-1);
4221 deexcitations[j].type.push_back(DxcTypeCollIon);
4222 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4223 deexcitations[j].nChannels += 2;
4224 } else if (level == "Ar_1S2") {
4225 // Rate constant from Velazco et al.
4226 const double kQ = 10.7e-19;
4227 const double pPenning = pPenningWK;
4228 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4229 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4230 deexcitations[j].final.push_back(-1);
4231 deexcitations[j].final.push_back(-1);
4232 deexcitations[j].type.push_back(DxcTypeCollIon);
4233 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4234 deexcitations[j].nChannels += 2;
4235 } else if (level == "Ar_2P8") {
4236 // Rate constant from Sadeghi et al., J. Chem. Phys. 115 (2001)
4237 const double kQ = 9.2e-19;
4238 double pPenning = fit4pEtaC2H6;
4239 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4240 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4241 deexcitations[j].final.push_back(-1);
4242 deexcitations[j].final.push_back(-1);
4243 deexcitations[j].type.push_back(DxcTypeCollIon);
4244 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4245 deexcitations[j].nChannels += 2;
4246 } else if (level == "Ar_2P6") {
4247 // Rate constant from Sadeghi et al.
4248 const double kQ = 4.8e-19;
4249 double pPenning = fit4pEtaC2H6;
4250 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4251 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4252 deexcitations[j].final.push_back(-1);
4253 deexcitations[j].final.push_back(-1);
4254 deexcitations[j].type.push_back(DxcTypeCollIon);
4255 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4256 deexcitations[j].nChannels += 2;
4257 } else if (level == "Ar_2P5") {
4258 // Rate constant from Sadeghi et al.
4259 const double kQ = 9.9e-19;
4260 double pPenning = fit4pEtaC2H6;
4261 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4262 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4263 deexcitations[j].final.push_back(-1);
4264 deexcitations[j].final.push_back(-1);
4265 deexcitations[j].type.push_back(DxcTypeCollIon);
4266 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4267 deexcitations[j].nChannels += 2;
4268 } else if (level == "Ar_2P1") {
4269 // Rate constant from Sadeghi et al.
4270 const double kQ = 11.0e-19;
4271 double pPenning = fit4pEtaC2H6;
4272 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4273 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4274 deexcitations[j].final.push_back(-1);
4275 deexcitations[j].final.push_back(-1);
4276 deexcitations[j].type.push_back(DxcTypeCollIon);
4277 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4278 deexcitations[j].nChannels += 2;
4279 } else if (level == "Ar_2P10" || level == "Ar_2P9" || level == "Ar_2P7" ||
4280 level == "Ar_2P4" || level == "Ar_2P3" || level == "Ar_2P2") {
4281 // Average of rate constants given by Sadeghi et al.
4282 const double kQ = 8.7e-19;
4283 double pPenning = fit4pEtaC2H6;
4284 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4285 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4286 deexcitations[j].final.push_back(-1);
4287 deexcitations[j].final.push_back(-1);
4288 deexcitations[j].type.push_back(DxcTypeCollIon);
4289 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4290 deexcitations[j].nChannels += 2;
4291 } else if (deexcitations[j].osc > 0.) {
4292 // Higher resonance levels
4293 // Calculate rate constant from Watanabe-Katsuura formula.
4294 const double m1 = ElectronMassGramme / (rgas[iAr] - 1.);
4295 const double m2 = ElectronMassGramme / (rgas[iC2H6] - 1.);
4296 // Compute the reduced mass.
4297 double mR = m1 * m2 / (m1 + m2);
4298 mR /= AtomicMassUnit;
4299 const double uA =
4300 (RydbergEnergy / deexcitations[j].energy) * deexcitations[j].osc;
4301 const double uQ =
4302 (2 * RydbergEnergy / deexcitations[j].energy) * pacs /
4303 (4 * Pi2 * FineStructureConstant * BohrRadius * BohrRadius);
4304 const double kQ =
4305 2.591e-19 * pow(uA * uQ, 2. / 5.) * pow(m_temperature / mR, 3. / 10.);
4306 if (m_debug) {
4307 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4308 std::cout << " Rate constant for coll. deexcitation of\n"
4309 << " " << level << " by C2H6 (W-K formula):\n"
4310 << " " << kQ << " cm3 ns-1\n";
4311 }
4312 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4313 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4314 deexcitations[j].final.push_back(-1);
4315 deexcitations[j].final.push_back(-1);
4316 deexcitations[j].type.push_back(DxcTypeCollIon);
4317 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4318 deexcitations[j].nChannels += 2;
4319 } else if (level == "Ar_3D6" || level == "Ar_3D3" || level == "Ar_3D4!" ||
4320 level == "Ar_3D4" || level == "Ar_3D1!!" ||
4321 level == "Ar_3D1!" || level == "Ar_3S1!!!!" ||
4322 level == "Ar_3S1!!" || level == "Ar_3S1!!!") {
4323 // Non-resonant 3d levels
4324 // Collision radii
4325 const double rAr3d = 436.e-10;
4326 const double rC2H6 = 195.e-10;
4327 // Hard sphere cross-section
4328 const double sigma = pow(rAr3d + rC2H6, 2) * Pi;
4329 // Reduced mass
4330 const double m1 = ElectronMass / (rgas[iAr] - 1.);
4331 const double m2 = ElectronMass / (rgas[iC2H6] - 1.);
4332 const double mR = m1 * m2 / (m1 + m2);
4333 // Relative velocity
4334 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
4335 m_temperature / (Pi * mR));
4336 const double kQ = fit3dQC2H6 * sigma * vel;
4337 if (m_debug) {
4338 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4339 std::cout << " Rate constant for coll. deexcitation of\n"
4340 << " " << level << " by C2H6 (hard sphere):\n"
4341 << " " << kQ << " cm3 ns-1\n";
4342 }
4343 double pPenning = fit3dEtaC2H6;
4344 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4345 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4346 deexcitations[j].final.push_back(-1);
4347 deexcitations[j].final.push_back(-1);
4348 deexcitations[j].type.push_back(DxcTypeCollIon);
4349 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4350 deexcitations[j].nChannels += 2;
4351 } else if (level == "Ar_2S5" || level == "Ar_2S3") {
4352 // Non-resonant 5s levels
4353 // Collision radii
4354 const double rAr5s = 635.e-10;
4355 const double rC2H6 = 195.e-10;
4356 // Hard sphere cross-section
4357 const double sigma = pow(rAr5s + rC2H6, 2) * Pi;
4358 // Reduced mass
4359 const double m1 = ElectronMass / (rgas[iAr] - 1.);
4360 const double m2 = ElectronMass / (rgas[iC2H6] - 1.);
4361 const double mR = m1 * m2 / (m1 + m2);
4362 // Relative velocity
4363 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
4364 m_temperature / (Pi * mR));
4365 const double kQ = fit3dQC2H6 * sigma * vel;
4366 if (m_debug) {
4367 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4368 std::cout << " Rate constant for coll. deexcitation of\n"
4369 << " " << level << " by C2H6 (hard sphere):\n"
4370 << " " << kQ << " cm3 ns-1\n";
4371 }
4372 double pPenning = fit3dEtaC2H6;
4373 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4374 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4375 deexcitations[j].final.push_back(-1);
4376 deexcitations[j].final.push_back(-1);
4377 deexcitations[j].type.push_back(DxcTypeCollIon);
4378 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4379 deexcitations[j].nChannels += 2;
4380 }
4381 }
4382 }
4383 if (withAr && withIso) {
4384 // Partial density of isobutane
4385 const double nQ = GetNumberDensity() * cIso;
4386 for (int j = nDeexcitations; j--;) {
4387 std::string level = deexcitations[j].label;
4388 // Photoabsorption cross-section and ionisation yield
4389 double pacs = 0., eta = 0.;
4390 // Use n-butane as approximation for isobutane.
4391 if (!optData.GetPhotoabsorptionCrossSection(
4392 "nC4H10", deexcitations[j].energy, pacs, eta)) {
4393 pacs = eta = 0.;
4394 }
4395 const double pPenningWK = pow(eta, 2. / 5.);
4396 if (level == "Ar_1S5") {
4397 // Rate constant from
4398 // Piper et al., J. Chem. Phys. 59 (1973), 3323-3340
4399 const double kQ = 7.1e-19;
4400 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4401 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4402 deexcitations[j].final.push_back(-1);
4403 deexcitations[j].final.push_back(-1);
4404 deexcitations[j].type.push_back(DxcTypeCollIon);
4405 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4406 deexcitations[j].nChannels += 2;
4407 } else if (level == "Ar_1S4") {
4408 // Rate constant from Piper et al.
4409 const double kQ = 6.1e-19;
4410 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4411 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4412 deexcitations[j].final.push_back(-1);
4413 deexcitations[j].final.push_back(-1);
4414 deexcitations[j].type.push_back(DxcTypeCollIon);
4415 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4416 deexcitations[j].nChannels += 2;
4417 } else if (level == "Ar_1S3") {
4418 // Rate constant for n-butane from
4419 // Velazco et al., J. Chem. Phys. 69 (1978)
4420 const double kQ = 8.5e-19;
4421 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4422 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4423 deexcitations[j].final.push_back(-1);
4424 deexcitations[j].final.push_back(-1);
4425 deexcitations[j].type.push_back(DxcTypeCollIon);
4426 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4427 deexcitations[j].nChannels += 2;
4428 } else if (level == "Ar_1S2") {
4429 // Rate constant from Piper et al.
4430 const double kQ = 11.0e-19;
4431 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4432 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4433 deexcitations[j].final.push_back(-1);
4434 deexcitations[j].final.push_back(-1);
4435 deexcitations[j].type.push_back(DxcTypeCollIon);
4436 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4437 deexcitations[j].nChannels += 2;
4438 } else if (level == "Ar_2P8") {
4439 // Rate constant for ethane
4440 const double kEth = 9.2e-19;
4441 // Ar radius [pm]
4442 const double r4p = 340.;
4443 // Molecular radii [pm]
4444 const double rEth = 195.;
4445 const double rIso = 250.;
4446 // Masses [amu]
4447 const double mAr = 39.9;
4448 const double mEth = 30.1;
4449 const double mIso = 58.1;
4450 // Estimate rate constant for isobutane.
4451 double kQ = kEth;
4452 kQ *= pow((r4p + rIso) / (r4p + rEth), 2) *
4453 sqrt((mEth / mIso) * (mAr + mIso) / (mAr + mEth));
4454 if (m_debug) {
4455 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4456 std::cout << " Estim. rate constant for coll. deexcitation of\n"
4457 << " " << level << " by iC4H10:\n"
4458 << " " << kQ << " cm3 ns-1\n";
4459 }
4460 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4461 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4462 deexcitations[j].final.push_back(-1);
4463 deexcitations[j].final.push_back(-1);
4464 deexcitations[j].type.push_back(DxcTypeCollIon);
4465 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4466 deexcitations[j].nChannels += 2;
4467 } else if (level == "Ar_2P6") {
4468 // Rate constant for ethane
4469 const double kEth = 4.8e-19;
4470 // Ar radius [pm]
4471 const double r4p = 340.;
4472 // Molecular radii [pm]
4473 const double rEth = 195.;
4474 const double rIso = 250.;
4475 // Masses [amu]
4476 const double mAr = 39.9;
4477 const double mEth = 30.1;
4478 const double mIso = 58.1;
4479 // Estimate rate constant for isobutane.
4480 double kQ = kEth;
4481 kQ *= pow((r4p + rIso) / (r4p + rEth), 2) *
4482 sqrt((mEth / mIso) * (mAr + mIso) / (mAr + mEth));
4483 if (m_debug) {
4484 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4485 std::cout << " Estim. rate constant for coll. deexcitation of\n"
4486 << " " << level << " by iC4H10:\n"
4487 << " " << kQ << " cm3 ns-1\n";
4488 }
4489 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4490 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4491 deexcitations[j].final.push_back(-1);
4492 deexcitations[j].final.push_back(-1);
4493 deexcitations[j].type.push_back(DxcTypeCollIon);
4494 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4495 deexcitations[j].nChannels += 2;
4496 } else if (level == "Ar_2P5") {
4497 // Rate constant for ethane
4498 const double kEth = 9.9e-19;
4499 // Ar radius [pm]
4500 const double r4p = 340.;
4501 // Molecular radii [pm]
4502 const double rEth = 195.;
4503 const double rIso = 250.;
4504 // Masses [amu]
4505 const double mAr = 39.9;
4506 const double mEth = 30.1;
4507 const double mIso = 58.1;
4508 // Estimate rate constant for isobutane.
4509 double kQ = kEth;
4510 kQ *= pow((r4p + rIso) / (r4p + rEth), 2) *
4511 sqrt((mEth / mIso) * (mAr + mIso) / (mAr + mEth));
4512 if (m_debug) {
4513 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4514 std::cout << " Estim. rate constant for coll. deexcitation of\n"
4515 << " " << level << " by iC4H10:\n"
4516 << " " << kQ << " cm3 ns-1\n";
4517 }
4518 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4519 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4520 deexcitations[j].final.push_back(-1);
4521 deexcitations[j].final.push_back(-1);
4522 deexcitations[j].type.push_back(DxcTypeCollIon);
4523 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4524 deexcitations[j].nChannels += 2;
4525 } else if (level == "Ar_2P1") {
4526 // Rate constant for Ethane
4527 const double kEth = 11.0e-19;
4528 // Ar radius [pm]
4529 const double r4p = 340.;
4530 // Molecular radii [pm]
4531 const double rEth = 195.;
4532 const double rIso = 250.;
4533 // Masses [amu]
4534 const double mAr = 39.9;
4535 const double mEth = 30.1;
4536 const double mIso = 58.1;
4537 // Estimate rate constant for isobutane.
4538 double kQ = kEth;
4539 kQ *= pow((r4p + rIso) / (r4p + rEth), 2) *
4540 sqrt((mEth / mIso) * (mAr + mIso) / (mAr + mEth));
4541 if (m_debug) {
4542 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4543 std::cout << " Estim. rate constant for coll. deexcitation of\n"
4544 << " " << level << " by iC4H10:\n"
4545 << " " << kQ << " cm3 ns-1\n";
4546 }
4547 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4548 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4549 deexcitations[j].final.push_back(-1);
4550 deexcitations[j].final.push_back(-1);
4551 deexcitations[j].type.push_back(DxcTypeCollIon);
4552 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4553 deexcitations[j].nChannels += 2;
4554 } else if (level == "Ar_2P10" || level == "Ar_2P9" || level == "Ar_2P7" ||
4555 level == "Ar_2P4" || level == "Ar_2P3" || level == "Ar_2P2") {
4556 // Rate constante for ethane
4557 const double kEth = 5.5e-19;
4558 // Ar radius [pm]
4559 const double r4p = 340.;
4560 // Molecular radii [pm]
4561 const double rEth = 195.;
4562 const double rIso = 250.;
4563 // Masses [amu]
4564 const double mAr = 39.9;
4565 const double mEth = 30.1;
4566 const double mIso = 58.1;
4567 // Estimate rate constant for isobutane.
4568 double kQ = kEth;
4569 kQ *= pow((r4p + rIso) / (r4p + rEth), 2) *
4570 sqrt((mEth / mIso) * (mAr + mIso) / (mAr + mEth));
4571 if (m_debug) {
4572 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4573 std::cout << " Estim. rate constant for coll. deexcitation of\n"
4574 << " " << level << " by iC4H10:\n"
4575 << " " << kQ << " cm3 ns-1\n";
4576 }
4577 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4578 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4579 deexcitations[j].final.push_back(-1);
4580 deexcitations[j].final.push_back(-1);
4581 deexcitations[j].type.push_back(DxcTypeCollIon);
4582 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4583 deexcitations[j].nChannels += 2;
4584 } else if (deexcitations[j].osc > 0.) {
4585 // Higher resonance levels
4586 // Calculate rate constant from Watanabe-Katsuura formula.
4587 const double m1 = ElectronMassGramme / (rgas[iAr] - 1.);
4588 const double m2 = ElectronMassGramme / (rgas[iIso] - 1.);
4589 // Compute the reduced mass.
4590 double mR = m1 * m2 / (m1 + m2);
4591 mR /= AtomicMassUnit;
4592 const double uA =
4593 (RydbergEnergy / deexcitations[j].energy) * deexcitations[j].osc;
4594 const double uQ =
4595 (2 * RydbergEnergy / deexcitations[j].energy) * pacs /
4596 (4 * Pi2 * FineStructureConstant * BohrRadius * BohrRadius);
4597 const double kQ =
4598 2.591e-19 * pow(uA * uQ, 2. / 5.) * pow(m_temperature / mR, 3. / 10.);
4599 if (m_debug) {
4600 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4601 std::cout << " Rate constant for coll. deexcitation of\n"
4602 << " " << level << " by C4H10 (W-K formula):\n"
4603 << " " << kQ << " cm3 ns-1\n";
4604 }
4605 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4606 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4607 deexcitations[j].final.push_back(-1);
4608 deexcitations[j].final.push_back(-1);
4609 deexcitations[j].type.push_back(DxcTypeCollIon);
4610 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4611 deexcitations[j].nChannels += 2;
4612 } else if (level == "Ar_3D6" || level == "Ar_3D3" || level == "Ar_3D4!" ||
4613 level == "Ar_3D4" || level == "Ar_3D1!!" ||
4614 level == "Ar_3D1!" || level == "Ar_3S1!!!!" ||
4615 level == "Ar_3S1!!" || level == "Ar_3S1!!!") {
4616 // Non-resonant 3d levels
4617 // Collision radii
4618 const double rAr3d = 436.e-10;
4619 const double rIso = 250.e-10;
4620 // Hard sphere cross-section
4621 const double sigma = pow(rAr3d + rIso, 2) * Pi;
4622 // Reduced mass
4623 const double m1 = ElectronMass / (rgas[iAr] - 1.);
4624 const double m2 = ElectronMass / (rgas[iIso] - 1.);
4625 const double mR = m1 * m2 / (m1 + m2);
4626 // Relative velocity
4627 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
4628 m_temperature / (Pi * mR));
4629 const double kQ = sigma * vel;
4630 if (m_debug) {
4631 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4632 std::cout << " Rate constant for coll. deexcitation of\n"
4633 << " " << level << " by iC4H10 (hard sphere):\n"
4634 << " " << kQ << " cm3 ns-1\n";
4635 }
4636 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4637 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4638 deexcitations[j].final.push_back(-1);
4639 deexcitations[j].final.push_back(-1);
4640 deexcitations[j].type.push_back(DxcTypeCollIon);
4641 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4642 deexcitations[j].nChannels += 2;
4643 } else if (level == "Ar_2S5" || level == "Ar_2S3") {
4644 // Non-resonant 5s levels
4645 // Collision radii
4646 const double rAr5s = 635.e-10;
4647 const double rIso = 250.e-10;
4648 // Hard sphere cross-section
4649 const double sigma = pow(rAr5s + rIso, 2) * Pi;
4650 // Reduced mass
4651 const double m1 = ElectronMass / (rgas[iAr] - 1.);
4652 const double m2 = ElectronMass / (rgas[iIso] - 1.);
4653 const double mR = m1 * m2 / (m1 + m2);
4654 // Relative velocity
4655 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
4656 m_temperature / (Pi * mR));
4657 const double kQ = sigma * vel;
4658 if (m_debug) {
4659 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4660 std::cout << " Rate constant for coll. deexcitation of\n"
4661 << " " << level << " by iC4H10 (hard sphere):\n"
4662 << " " << kQ << " cm3 ns-1\n";
4663 }
4664 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4665 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4666 deexcitations[j].final.push_back(-1);
4667 deexcitations[j].final.push_back(-1);
4668 deexcitations[j].type.push_back(DxcTypeCollIon);
4669 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4670 deexcitations[j].nChannels += 2;
4671 }
4672 }
4673 }
4674 if (withAr && withC2H2) {
4675 // Partial density of acetylene
4676 const double nQ = GetNumberDensity() * cC2H2;
4677 for (int j = nDeexcitations; j--;) {
4678 std::string level = deexcitations[j].label;
4679 // Photoabsorption cross-section and ionisation yield
4680 double pacs = 0., eta = 0.;
4681 if (!optData.GetPhotoabsorptionCrossSection(
4682 "C2H2", deexcitations[j].energy, pacs, eta)) {
4683 pacs = eta = 0.;
4684 }
4685 const double pPenningWK = pow(eta, 2. / 5.);
4686 if (level == "Ar_1S5") {
4687 // Rate constant from Velazco et al., J. Chem. Phys. 69 (1978)
4688 const double kQ = 5.6e-19;
4689 // Branching ratio for ionization according to
4690 // Jones et al., J. Phys. Chem. 89 (1985)
4691 // p = 0.61, p = 0.74 (agrees roughly with WK estimate)
4692 const double pPenning = 0.61;
4693 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4694 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4695 deexcitations[j].final.push_back(-1);
4696 deexcitations[j].final.push_back(-1);
4697 deexcitations[j].type.push_back(DxcTypeCollIon);
4698 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4699 deexcitations[j].nChannels += 2;
4700 } else if (level == "Ar_1S4") {
4701 // Rate constant from Velazco et al.
4702 const double kQ = 4.6e-19;
4703 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4704 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4705 deexcitations[j].final.push_back(-1);
4706 deexcitations[j].final.push_back(-1);
4707 deexcitations[j].type.push_back(DxcTypeCollIon);
4708 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4709 deexcitations[j].nChannels += 2;
4710 } else if (level == "Ar_1S3") {
4711 const double kQ = 5.6e-19;
4712 const double pPenning = 0.61;
4713 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4714 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4715 deexcitations[j].final.push_back(-1);
4716 deexcitations[j].final.push_back(-1);
4717 deexcitations[j].type.push_back(DxcTypeCollIon);
4718 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4719 deexcitations[j].nChannels += 2;
4720 } else if (level == "Ar_1S2") {
4721 // Rate constant from Velazco et al.
4722 const double kQ = 8.7e-19;
4723 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4724 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4725 deexcitations[j].final.push_back(-1);
4726 deexcitations[j].final.push_back(-1);
4727 deexcitations[j].type.push_back(DxcTypeCollIon);
4728 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4729 deexcitations[j].nChannels += 2;
4730 } else if (level == "Ar_2P8") {
4731 // Rate constant from Sadeghi et al., J. Chem. Phys. 115 (2001)
4732 const double kQ = 5.0e-19;
4733 const double pPenning = 0.3;
4734 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4735 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4736 deexcitations[j].final.push_back(-1);
4737 deexcitations[j].final.push_back(-1);
4738 deexcitations[j].type.push_back(DxcTypeCollIon);
4739 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4740 deexcitations[j].nChannels += 2;
4741 } else if (level == "Ar_2P6") {
4742 // Rate constant from Sadeghi et al.
4743 const double kQ = 5.7e-19;
4744 const double pPenning = 0.3;
4745 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4746 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4747 deexcitations[j].final.push_back(-1);
4748 deexcitations[j].final.push_back(-1);
4749 deexcitations[j].type.push_back(DxcTypeCollIon);
4750 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4751 deexcitations[j].nChannels += 2;
4752 } else if (level == "Ar_2P5") {
4753 // Rate constant from Sadeghi et al.
4754 const double kQ = 6.0e-19;
4755 const double pPenning = 0.3;
4756 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4757 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4758 deexcitations[j].final.push_back(-1);
4759 deexcitations[j].final.push_back(-1);
4760 deexcitations[j].type.push_back(DxcTypeCollIon);
4761 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4762 deexcitations[j].nChannels += 2;
4763 } else if (level == "Ar_2P1") {
4764 // Rate constant from Sadeghi et al.
4765 const double kQ = 5.3e-19;
4766 const double pPenning = 0.3;
4767 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4768 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4769 deexcitations[j].final.push_back(-1);
4770 deexcitations[j].final.push_back(-1);
4771 deexcitations[j].type.push_back(DxcTypeCollIon);
4772 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4773 deexcitations[j].nChannels += 2;
4774 } else if (level == "Ar_2P10" || level == "Ar_2P9" || level == "Ar_2P7" ||
4775 level == "Ar_2P4" || level == "Ar_2P3" || level == "Ar_2P2") {
4776 // Average of rate constants given by Sadeghi et al.
4777 const double kQ = 5.5e-19;
4778 const double pPenning = 0.3;
4779 deexcitations[j].p.push_back(kQ * nQ * pPenning);
4780 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenning));
4781 deexcitations[j].final.push_back(-1);
4782 deexcitations[j].final.push_back(-1);
4783 deexcitations[j].type.push_back(DxcTypeCollIon);
4784 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4785 deexcitations[j].nChannels += 2;
4786 } else if (deexcitations[j].osc > 0.) {
4787 // Higher resonance levels
4788 // Calculate rate constant from Watanabe-Katsuura formula.
4789 const double m1 = ElectronMassGramme / (rgas[iAr] - 1.);
4790 const double m2 = ElectronMassGramme / (rgas[iC2H2] - 1.);
4791 // Compute the reduced mass.
4792 double mR = m1 * m2 / (m1 + m2);
4793 mR /= AtomicMassUnit;
4794 const double uA =
4795 (RydbergEnergy / deexcitations[j].energy) * deexcitations[j].osc;
4796 const double uQ =
4797 (2 * RydbergEnergy / deexcitations[j].energy) * pacs /
4798 (4 * Pi2 * FineStructureConstant * BohrRadius * BohrRadius);
4799 const double kQ =
4800 2.591e-19 * pow(uA * uQ, 2. / 5.) * pow(m_temperature / mR, 3. / 10.);
4801 if (m_debug) {
4802 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4803 std::cout << " Rate constant for coll. deexcitation of\n"
4804 << " " << level << " by C2H2 (W-K formula):\n"
4805 << " " << kQ << " cm3 ns-1\n";
4806 }
4807 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4808 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4809 deexcitations[j].final.push_back(-1);
4810 deexcitations[j].final.push_back(-1);
4811 deexcitations[j].type.push_back(DxcTypeCollIon);
4812 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4813 deexcitations[j].nChannels += 2;
4814 } else if (level == "Ar_3D6" || level == "Ar_3D3" || level == "Ar_3D4!" ||
4815 level == "Ar_3D4" || level == "Ar_3D1!!" ||
4816 level == "Ar_3D1!" || level == "Ar_3S1!!!!" ||
4817 level == "Ar_3S1!!" || level == "Ar_3S1!!!") {
4818 // Non-resonant 3d levels
4819 // Collision radii
4820 const double rAr3d = 436.e-10;
4821 const double rC2H2 = 165.e-10;
4822 // Hard sphere cross-section
4823 const double sigma = pow(rAr3d + rC2H2, 2) * Pi;
4824 // Reduced mass
4825 const double m1 = ElectronMass / (rgas[iAr] - 1.);
4826 const double m2 = ElectronMass / (rgas[iC2H2] - 1.);
4827 const double mR = m1 * m2 / (m1 + m2);
4828 // Relative velocity
4829 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
4830 m_temperature / (Pi * mR));
4831 const double kQ = sigma * vel;
4832 if (m_debug) {
4833 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4834 std::cout << " Rate constant for coll. deexcitation of\n"
4835 << " " << level << " by C2H2 (hard sphere):\n"
4836 << " " << kQ << " cm3 ns-1\n";
4837 }
4838 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4839 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4840 deexcitations[j].final.push_back(-1);
4841 deexcitations[j].final.push_back(-1);
4842 deexcitations[j].type.push_back(DxcTypeCollIon);
4843 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4844 deexcitations[j].nChannels += 2;
4845 } else if (level == "Ar_2S5" || level == "Ar_2S3") {
4846 // Non-resonant 5s levels
4847 // Collision radii
4848 const double rAr5s = 635.e-10;
4849 const double rC2H2 = 165.e-10;
4850 // Hard sphere cross-section
4851 const double sigma = pow(rAr5s + rC2H2, 2) * Pi;
4852 // Reduced mass
4853 const double m1 = ElectronMass / (rgas[iAr] - 1.);
4854 const double m2 = ElectronMass / (rgas[iC2H2] - 1.);
4855 const double mR = m1 * m2 / (m1 + m2);
4856 // Relative velocity
4857 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
4858 m_temperature / (Pi * mR));
4859 const double kQ = sigma * vel;
4860 if (m_debug) {
4861 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4862 std::cout << " Rate constant for coll. deexcitation of\n"
4863 << " " << level << " by C2H2 (hard sphere):\n"
4864 << " " << kQ << " cm3 ns-1\n";
4865 }
4866 deexcitations[j].p.push_back(kQ * nQ * pPenningWK);
4867 deexcitations[j].p.push_back(kQ * nQ * (1. - pPenningWK));
4868 deexcitations[j].final.push_back(-1);
4869 deexcitations[j].final.push_back(-1);
4870 deexcitations[j].type.push_back(DxcTypeCollIon);
4871 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4872 deexcitations[j].nChannels += 2;
4873 }
4874 }
4875 }
4876 if (withAr && withCF4) {
4877 // Partial density of CF4
4878 const double nQ = GetNumberDensity() * cCF4;
4879 for (int j = nDeexcitations; j--;) {
4880 std::string level = deexcitations[j].label;
4881 // Photoabsorption cross-section and ionisation yield
4882 double pacs = 0., eta = 0.;
4883 if (!optData.GetPhotoabsorptionCrossSection(
4884 "CF4", deexcitations[j].energy, pacs, eta)) {
4885 pacs = eta = 0.;
4886 }
4887 if (level == "Ar_1S5") {
4888 // Rate constant from Chen and Setser
4889 const double kQ = 0.33e-19;
4890 deexcitations[j].p.push_back(kQ * nQ);
4891 deexcitations[j].final.push_back(-1);
4892 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4893 deexcitations[j].nChannels += 1;
4894 } else if (level == "Ar_1S3") {
4895 // Rate constant from Chen and Setser
4896 const double kQ = 0.26e-19;
4897 deexcitations[j].p.push_back(kQ * nQ);
4898 deexcitations[j].final.push_back(-1);
4899 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4900 deexcitations[j].nChannels += 1;
4901 } else if (level == "Ar_2P8") {
4902 // Rate constant from Sadeghi et al.
4903 const double kQ = 1.7e-19;
4904 deexcitations[j].p.push_back(kQ * nQ);
4905 deexcitations[j].final.push_back(-1);
4906 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4907 deexcitations[j].nChannels += 1;
4908 } else if (level == "Ar_2P6") {
4909 // Rate constant from Sadeghi et al.
4910 const double kQ = 1.7e-19;
4911 deexcitations[j].p.push_back(kQ * nQ);
4912 deexcitations[j].final.push_back(-1);
4913 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4914 deexcitations[j].nChannels += 1;
4915 } else if (level == "Ar_2P5") {
4916 // Rate constant from Sadeghi et al.
4917 const double kQ = 1.6e-19;
4918 deexcitations[j].p.push_back(kQ * nQ);
4919 deexcitations[j].final.push_back(-1);
4920 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4921 deexcitations[j].nChannels += 1;
4922 } else if (level == "Ar_2P1") {
4923 // Rate constant from Sadeghi et al.
4924 const double kQ = 2.2e-19;
4925 deexcitations[j].p.push_back(kQ * nQ);
4926 deexcitations[j].final.push_back(-1);
4927 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4928 deexcitations[j].nChannels += 1;
4929 } else if (level == "Ar_2P10" || level == "Ar_2P9" || level == "Ar_2P7" ||
4930 level == "Ar_2P4" || level == "Ar_2P3" || level == "Ar_2P2") {
4931 // Average of 4p rate constants from Sadeghi et al.
4932 const double kQ = 1.8e-19;
4933 deexcitations[j].p.push_back(kQ * nQ);
4934 deexcitations[j].final.push_back(-1);
4935 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4936 deexcitations[j].nChannels += 1;
4937 } else if (deexcitations[j].osc > 0.) {
4938 // Resonance levels
4939 // Calculate rate constant from Watanabe-Katsuura formula.
4940 const double m1 = ElectronMassGramme / (rgas[iAr] - 1.);
4941 const double m2 = ElectronMassGramme / (rgas[iCF4] - 1.);
4942 // Compute the reduced mass.
4943 double mR = m1 * m2 / (m1 + m2);
4944 mR /= AtomicMassUnit;
4945 const double uA =
4946 (RydbergEnergy / deexcitations[j].energy) * deexcitations[j].osc;
4947 const double uQ =
4948 (2 * RydbergEnergy / deexcitations[j].energy) * pacs /
4949 (4 * Pi2 * FineStructureConstant * BohrRadius * BohrRadius);
4950 const double kQ =
4951 2.591e-19 * pow(uA * uQ, 2. / 5.) * pow(m_temperature / mR, 3. / 10.);
4952 if (m_debug) {
4953 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4954 std::cout << " Rate constant for coll. deexcitation of\n"
4955 << " " << level << " by CF4 (W-K formula):\n"
4956 << " " << kQ << " cm3 ns-1\n";
4957 }
4958 deexcitations[j].p.push_back(kQ * nQ);
4959 deexcitations[j].final.push_back(-1);
4960 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4961 deexcitations[j].nChannels += 1;
4962 } else if (level == "Ar_3D6" || level == "Ar_3D3" || level == "Ar_3D4!" ||
4963 level == "Ar_3D4" || level == "Ar_3D1!!" ||
4964 level == "Ar_3D1!" || level == "Ar_3S1!!!!" ||
4965 level == "Ar_3S1!!" || level == "Ar_3S1!!!") {
4966 // Non-resonant 3d levels
4967 // Collision radii
4968 const double rAr3d = 436.e-10;
4969 const double rCF4 = 235.e-10;
4970 // Hard sphere cross-section
4971 const double sigma = pow(rAr3d + rCF4, 2) * Pi;
4972 // Reduced mass
4973 const double m1 = ElectronMass / (rgas[iAr] - 1.);
4974 const double m2 = ElectronMass / (rgas[iCF4] - 1.);
4975 const double mR = m1 * m2 / (m1 + m2);
4976 // Relative velocity
4977 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
4978 m_temperature / (Pi * mR));
4979 const double kQ = sigma * vel;
4980 if (m_debug) {
4981 std::cout << m_className << "::ComputeDeexcitationTable:\n";
4982 std::cout << " Rate constant for coll. deexcitation of\n"
4983 << " " << level << " by CF4 (hard sphere):\n"
4984 << " " << kQ << " cm3 ns-1\n";
4985 }
4986 deexcitations[j].p.push_back(kQ * nQ);
4987 deexcitations[j].final.push_back(-1);
4988 deexcitations[j].type.push_back(DxcTypeCollNonIon);
4989 deexcitations[j].nChannels += 1;
4990 } else if (level == "Ar_2S5" || level == "Ar_2S3") {
4991 // Non-resonant 5s levels
4992 // Collision radii
4993 const double rAr5s = 635.e-10;
4994 const double rCF4 = 190.e-10;
4995 // Hard sphere cross-section
4996 const double sigma = pow(rAr5s + rCF4, 2) * Pi;
4997 // Reduced mass
4998 const double m1 = ElectronMass / (rgas[iAr] - 1.);
4999 const double m2 = ElectronMass / (rgas[iCF4] - 1.);
5000 const double mR = m1 * m2 / (m1 + m2);
5001 // Relative velocity
5002 const double vel = SpeedOfLight * sqrt(8. * BoltzmannConstant *
5003 m_temperature / (Pi * mR));
5004 const double kQ = sigma * vel;
5005 if (m_debug) {
5006 std::cout << m_className << "::ComputeDeexcitationTable:\n";
5007 std::cout << " Rate constant for coll. deexcitation of\n"
5008 << " " << level << " by CF4 (hard sphere):\n"
5009 << " " << kQ << " cm3 ns-1\n";
5010 }
5011 deexcitations[j].p.push_back(kQ * nQ);
5012 deexcitations[j].final.push_back(-1);
5013 deexcitations[j].type.push_back(DxcTypeCollNonIon);
5014 deexcitations[j].nChannels += 1;
5015 }
5016 }
5017 }
5018
5019 if ((m_debug || verbose) && nDeexcitations > 0) {
5020 std::cout << m_className << "::ComputeDeexcitationTable:\n";
5021 std::cout << " Level Energy [eV] "
5022 << " Lifetimes [ns]\n";
5023 std::cout << " "
5024 << " Total Radiative "
5025 << " Collisional\n";
5026 std::cout << " "
5027 << " Ionisation Transfer Loss\n";
5028 }
5029
5030 for (int i = 0; i < nDeexcitations; ++i) {
5031 // Calculate the total decay rate of each level.
5032 deexcitations[i].rate = 0.;
5033 double fRad = 0.;
5034 double fCollIon = 0., fCollTransfer = 0., fCollLoss = 0.;
5035 for (int j = deexcitations[i].nChannels; j--;) {
5036 deexcitations[i].rate += deexcitations[i].p[j];
5037 if (deexcitations[i].type[j] == DxcTypeRad) {
5038 fRad += deexcitations[i].p[j];
5039 } else if (deexcitations[i].type[j] == DxcTypeCollIon) {
5040 fCollIon += deexcitations[i].p[j];
5041 } else if (deexcitations[i].type[j] == DxcTypeCollNonIon) {
5042 if (deexcitations[i].final[j] < 0) {
5043 fCollLoss += deexcitations[i].p[j];
5044 } else {
5045 fCollTransfer += deexcitations[i].p[j];
5046 }
5047 } else {
5048 std::cerr << m_className << "::ComputeDeexcitationTable:\n";
5049 std::cerr << " Unknown type of deexcitation channel (level "
5050 << deexcitations[i].label << ")\n";
5051 std::cerr << " Program bug!\n";
5052 }
5053 }
5054 if (deexcitations[i].rate > 0.) {
5055 // Print the radiative and collisional decay rates.
5056 if (m_debug || verbose) {
5057 std::cout << std::setw(12) << deexcitations[i].label << " "
5058 << std::fixed << std::setprecision(3) << std::setw(7)
5059 << deexcitations[i].energy << " " << std::setw(10)
5060 << 1. / deexcitations[i].rate << " ";
5061 if (fRad > 0.) {
5062 std::cout << std::fixed << std::setprecision(3) << std::setw(10)
5063 << 1. / fRad << " ";
5064 } else {
5065 std::cout << "---------- ";
5066 }
5067 if (fCollIon > 0.) {
5068 std::cout << std::fixed << std::setprecision(3) << std::setw(10)
5069 << 1. / fCollIon << " ";
5070 } else {
5071 std::cout << "---------- ";
5072 }
5073 if (fCollTransfer > 0.) {
5074 std::cout << std::fixed << std::setprecision(3) << std::setw(10)
5075 << 1. / fCollTransfer << " ";
5076 } else {
5077 std::cout << "---------- ";
5078 }
5079 if (fCollLoss > 0.) {
5080 std::cout << std::fixed << std::setprecision(3) << std::setw(10)
5081 << 1. / fCollLoss << "\n";
5082 } else {
5083 std::cout << "---------- \n";
5084 }
5085 }
5086 // Normalise the decay branching ratios.
5087 for (int j = 0; j < deexcitations[i].nChannels; ++j) {
5088 deexcitations[i].p[j] /= deexcitations[i].rate;
5089 if (j > 0) deexcitations[i].p[j] += deexcitations[i].p[j - 1];
5090 }
5091 }
5092 }
5093}
5094
5095void MediumMagboltz::ComputeDeexcitation(int iLevel, int& fLevel) {
5096
5097 if (!useDeexcitation) {
5098 std::cerr << m_className << "::ComputeDeexcitation:\n";
5099 std::cerr << " Deexcitation is disabled.\n";
5100 return;
5101 }
5102
5103 // Make sure that the tables are updated.
5104 if (m_isChanged) {
5105 if (!Mixer()) {
5106 std::cerr << m_className << "::ComputeDeexcitation:\n";
5107 std::cerr << " Error calculating the collision rates table.\n";
5108 return;
5109 }
5110 m_isChanged = false;
5111 }
5112
5113 if (iLevel < 0 || iLevel >= nTerms) {
5114 std::cerr << m_className << "::ComputeDeexcitation:\n";
5115 std::cerr << " Level index is out of range.\n";
5116 return;
5117 }
5118
5119 iLevel = iDeexcitation[iLevel];
5120 if (iLevel < 0 || iLevel >= nDeexcitations) {
5121 std::cerr << m_className << "::ComputeDeexcitation:\n";
5122 std::cerr << " Level is not deexcitable.\n";
5123 return;
5124 }
5125
5126 ComputeDeexcitationInternal(iLevel, fLevel);
5127 if (fLevel >= 0 && fLevel < nDeexcitations) {
5128 fLevel = deexcitations[fLevel].level;
5129 }
5130}
5131
5132void MediumMagboltz::ComputeDeexcitationInternal(int iLevel, int& fLevel) {
5133
5134 nDeexcitationProducts = 0;
5135 dxcProducts.clear();
5136
5137 dxcProd newDxcProd;
5138 newDxcProd.s = 0.;
5139 newDxcProd.t = 0.;
5140
5141 fLevel = iLevel;
5142 while (iLevel >= 0 && iLevel < nDeexcitations) {
5143 if (deexcitations[iLevel].rate <= 0. ||
5144 deexcitations[iLevel].nChannels <= 0) {
5145 // This level is a dead end.
5146 fLevel = iLevel;
5147 return;
5148 }
5149 // Determine the de-excitation time.
5150 newDxcProd.t += -log(RndmUniformPos()) / deexcitations[iLevel].rate;
5151 // Select the transition.
5152 fLevel = -1;
5153 int type = DxcTypeRad;
5154 const double r = RndmUniform();
5155 for (int j = 0; j < deexcitations[iLevel].nChannels; ++j) {
5156 if (r <= deexcitations[iLevel].p[j]) {
5157 fLevel = deexcitations[iLevel].final[j];
5158 type = deexcitations[iLevel].type[j];
5159 break;
5160 }
5161 }
5162 if (type == DxcTypeRad) {
5163 // Radiative decay
5164 newDxcProd.type = DxcProdTypePhoton;
5165 newDxcProd.energy = deexcitations[iLevel].energy;
5166 if (fLevel >= 0) {
5167 // Decay to a lower lying excited state.
5168 newDxcProd.energy -= deexcitations[fLevel].energy;
5169 if (newDxcProd.energy < Small) newDxcProd.energy = Small;
5170 dxcProducts.push_back(newDxcProd);
5171 ++nDeexcitationProducts;
5172 // Proceed with the next level in the cascade.
5173 iLevel = fLevel;
5174 } else {
5175 // Decay to ground state.
5176 double delta = RndmVoigt(0., deexcitations[iLevel].sDoppler,
5177 deexcitations[iLevel].gPressure);
5178 while (newDxcProd.energy + delta < Small ||
5179 fabs(delta) >= deexcitations[iLevel].width) {
5180 delta = RndmVoigt(0., deexcitations[iLevel].sDoppler,
5181 deexcitations[iLevel].gPressure);
5182 }
5183 newDxcProd.energy += delta;
5184 dxcProducts.push_back(newDxcProd);
5185 ++nDeexcitationProducts;
5186 // Deexcitation cascade is over.
5187 fLevel = iLevel;
5188 return;
5189 }
5190 } else if (type == DxcTypeCollIon) {
5191 // Ionisation electron
5192 newDxcProd.type = DxcProdTypeElectron;
5193 newDxcProd.energy = deexcitations[iLevel].energy;
5194 if (fLevel >= 0) {
5195 // Associative ionisation
5196 newDxcProd.energy -= deexcitations[fLevel].energy;
5197 if (newDxcProd.energy < Small) newDxcProd.energy = Small;
5198 ++nPenning;
5199 dxcProducts.push_back(newDxcProd);
5200 ++nDeexcitationProducts;
5201 // Proceed with the next level in the cascade.
5202 iLevel = fLevel;
5203 } else {
5204 // Penning ionisation
5205 newDxcProd.energy -= minIonPot;
5206 if (newDxcProd.energy < Small) newDxcProd.energy = Small;
5207 ++nPenning;
5208 dxcProducts.push_back(newDxcProd);
5209 ++nDeexcitationProducts;
5210 // Deexcitation cascade is over.
5211 fLevel = iLevel;
5212 return;
5213 }
5214 } else if (type == DxcTypeCollNonIon) {
5215 // Proceed with the next level in the cascade.
5216 iLevel = fLevel;
5217 } else {
5218 std::cerr << m_className << "::ComputeDeexcitationInternal:\n";
5219 std::cerr << " Unknown deexcitation channel type (" << type << ").\n";
5220 std::cerr << " Program bug!\n";
5221 // Abort the deexcitation calculation.
5222 fLevel = iLevel;
5223 return;
5224 }
5225 }
5226}
5227
5228bool MediumMagboltz::ComputePhotonCollisionTable(const bool verbose) {
5229
5230 OpticalData data;
5231 double cs;
5232 double eta;
5233
5234 // Atomic density
5235 const double dens = GetNumberDensity();
5236
5237 // Reset the collision rate arrays.
5238 cfTotGamma.clear();
5239 cfTotGamma.resize(nEnergyStepsGamma, 0.);
5240 cfGamma.clear();
5241 cfGamma.resize(nEnergyStepsGamma);
5242 for (int j = nEnergyStepsGamma; j--;) cfGamma[j].clear();
5243 csTypeGamma.clear();
5244
5245 nPhotonTerms = 0;
5246 for (unsigned int i = 0; i < m_nComponents; ++i) {
5247 const double prefactor = dens * SpeedOfLight * fraction[i];
5248 // Check if optical data for this gas is available.
5249 std::string gasname = gas[i];
5250 if (gasname == "iC4H10") {
5251 gasname = "nC4H10";
5252 if (m_debug || verbose) {
5253 std::cout << m_className << "::ComputePhotonCollisionTable:\n";
5254 std::cout << " Photoabsorption cross-section for "
5255 << "iC4H10 not available.\n";
5256 std::cout << " Using n-butane cross-section instead.\n";
5257 }
5258 }
5259 if (!data.IsAvailable(gasname)) return false;
5260 csTypeGamma.push_back(i * nCsTypesGamma + PhotonCollisionTypeIonisation);
5261 csTypeGamma.push_back(i * nCsTypesGamma + PhotonCollisionTypeInelastic);
5262 nPhotonTerms += 2;
5263 for (int j = 0; j < nEnergyStepsGamma; ++j) {
5264 // Retrieve total photoabsorption cross-section and ionisation yield.
5265 data.GetPhotoabsorptionCrossSection(gasname, (j + 0.5) * eStepGamma, cs,
5266 eta);
5267 cfTotGamma[j] += cs * prefactor;
5268 // Ionisation
5269 cfGamma[j].push_back(cs * prefactor * eta);
5270 // Inelastic absorption
5271 cfGamma[j].push_back(cs * prefactor * (1. - eta));
5272 }
5273 }
5274
5275 // If requested, write the cross-sections to file.
5276 if (useCsOutput) {
5277 std::ofstream csfile;
5278 csfile.open("csgamma.txt", std::ios::out);
5279 for (int j = 0; j < nEnergyStepsGamma; ++j) {
5280 csfile << (j + 0.5) * eStepGamma << " ";
5281 for (int i = 0; i < nPhotonTerms; ++i) csfile << cfGamma[j][i] << " ";
5282 csfile << "\n";
5283 }
5284 csfile.close();
5285 }
5286
5287 // Calculate the cumulative rates.
5288 for (int j = 0; j < nEnergyStepsGamma; ++j) {
5289 for (int i = 0; i < nPhotonTerms; ++i) {
5290 if (i > 0) cfGamma[j][i] += cfGamma[j][i - 1];
5291 }
5292 }
5293
5294 if (m_debug || verbose) {
5295 std::cout << m_className << "::ComputePhotonCollisionTable:\n";
5296 std::cout << " Energy [eV] Mean free path [um]\n";
5297 for (int i = 0; i < 10; ++i) {
5298 const double imfp =
5299 cfTotGamma[(2 * i + 1) * nEnergyStepsGamma / 20] / SpeedOfLight;
5300 std::cout << " " << std::fixed << std::setw(10) << std::setprecision(2)
5301 << (2 * i + 1) * eFinalGamma / 20 << " " << std::setw(18)
5302 << std::setprecision(4);
5303 if (imfp > 0.) {
5304 std::cout << 1.e4 / imfp << "\n";
5305 } else {
5306 std::cout << "------------\n";
5307 }
5308 }
5309 std::cout << std::resetiosflags(std::ios_base::floatfield);
5310 }
5311
5312 if (!useDeexcitation) return true;
5313
5314 // Conversion factor from oscillator strength to cross-section
5315 const double f2cs =
5316 FineStructureConstant * 2 * Pi2 * HbarC * HbarC / ElectronMass;
5317 // Discrete absorption lines
5318 int nResonanceLines = 0;
5319 for (int i = 0; i < nDeexcitations; ++i) {
5320 if (deexcitations[i].osc < Small) continue;
5321 const double prefactor =
5322 dens * SpeedOfLight * fraction[deexcitations[i].gas];
5323 deexcitations[i].cf = prefactor * f2cs * deexcitations[i].osc;
5324 // Compute the line width due to Doppler broadening.
5325 const double mgas = ElectronMass / (rgas[deexcitations[i].gas] - 1.);
5326 const double wDoppler = sqrt(BoltzmannConstant * m_temperature / mgas);
5327 deexcitations[i].sDoppler = wDoppler * deexcitations[i].energy;
5328 // Compute the half width at half maximum due to resonance broadening.
5329 // A. W. Ali and H. R. Griem, Phys. Rev. 140, 1044
5330 // A. W. Ali and H. R. Griem, Phys. Rev. 144, 366
5331 const double kResBroad = 1.92 * Pi * sqrt(1. / 3.);
5332 deexcitations[i].gPressure = kResBroad * FineStructureConstant *
5333 pow(HbarC, 3) * deexcitations[i].osc * dens *
5334 fraction[deexcitations[i].gas] /
5335 (ElectronMass * deexcitations[i].energy);
5336 // Make an estimate for the width within which a photon can be
5337 // absorbed by the line
5338 // const int nWidths = 1000;
5339 const double nWidths = fitLineCut;
5340 // Calculate the FWHM of the Voigt distribution according to the
5341 // approximation formula given in
5342 // Olivero and Longbothum, J. Quant. Spectr. Rad. Trans. 17, 233-236
5343 const double fwhmGauss = deexcitations[i].sDoppler * sqrt(2. * log(2.));
5344 const double fwhmLorentz = deexcitations[i].gPressure;
5345 const double fwhmVoigt =
5346 0.5 * (1.0692 * fwhmLorentz + sqrt(0.86639 * fwhmLorentz * fwhmLorentz +
5347 4 * fwhmGauss * fwhmGauss));
5348 deexcitations[i].width = nWidths * fwhmVoigt;
5349 ++nResonanceLines;
5350 }
5351
5352 if (nResonanceLines <= 0) {
5353 std::cerr << m_className << "::ComputePhotonCollisionTable:\n";
5354 std::cerr << " No resonance lines found.\n";
5355 return true;
5356 }
5357
5358 if (m_debug || verbose) {
5359 std::cout << m_className << "::ComputePhotonCollisionTable:\n";
5360 std::cout << " Discrete absorption lines:\n";
5361 std::cout << " Energy [eV] Line width (FWHM) [eV] "
5362 << " Mean free path [um]\n";
5363 std::cout << " Doppler Pressure "
5364 << " (peak) \n";
5365 for (int i = 0; i < nDeexcitations; ++i) {
5366 if (deexcitations[i].osc < Small) continue;
5367 const double imfpP = (deexcitations[i].cf / SpeedOfLight) *
5368 TMath::Voigt(0., deexcitations[i].sDoppler,
5369 2 * deexcitations[i].gPressure);
5370 std::cout << " " << std::fixed << std::setw(6)
5371 << std::setprecision(3) << deexcitations[i].energy << " +/- "
5372 << std::scientific << std::setprecision(1)
5373 << deexcitations[i].width << " " << std::setprecision(2)
5374 << 2 * sqrt(2 * log(2.)) * deexcitations[i].sDoppler << " "
5375 << std::scientific << std::setprecision(3)
5376 << 2 * deexcitations[i].gPressure << " " << std::fixed
5377 << std::setw(10) << std::setprecision(4);
5378 if (imfpP > 0.) {
5379 std::cout << 1.e4 / imfpP;
5380 } else {
5381 std::cout << "----------";
5382 }
5383 std::cout << "\n";
5384 }
5385 }
5386
5387 return true;
5388}
5389
5390void MediumMagboltz::RunMagboltz(const double e, const double bmag,
5391 const double btheta, const int ncoll,
5392 bool verbose, double& vx, double& vy,
5393 double& vz, double& dl, double& dt,
5394 double& alpha, double& eta, double& vxerr,
5395 double& vyerr, double& vzerr, double& dlerr,
5396 double& dterr, double& alphaerr,
5397 double& etaerr, double& alphatof) {
5398
5399 // Initialize the values.
5400 vx = vy = vz = 0.;
5401 dl = dt = 0.;
5402 alpha = eta = alphatof = 0.;
5403 vxerr = vyerr = vzerr = 0.;
5404 dlerr = dterr = 0.;
5405 alphaerr = etaerr = 0.;
5406
5407 // Set input parameters in Magboltz common blocks.
5409 Magboltz::inpt_.nStep = 4000;
5410 Magboltz::inpt_.nAniso = 2;
5411
5412 Magboltz::inpt_.tempc = m_temperature - ZeroCelsius;
5414 Magboltz::inpt_.ipen = 0;
5415 Magboltz::setp_.nmax = ncoll;
5416
5417 Magboltz::setp_.efield = e;
5418 // Convert from Tesla to kGauss.
5419 Magboltz::bfld_.bmag = bmag * 10.;
5420 // Convert from radians to degree.
5421 Magboltz::bfld_.btheta = btheta * 180. / Pi;
5422
5423 // Set the gas composition in Magboltz.
5424 for (unsigned int i = 0; i < m_nComponents; ++i) {
5425 int ng = 0;
5426 if (!GetGasNumberMagboltz(gas[i], ng)) {
5427 std::cerr << m_className << "::RunMagboltz:\n";
5428 std::cerr << " Gas " << gas[i] << " has no corresponding"
5429 << " gas number in Magboltz.\n";
5430 return;
5431 }
5432 Magboltz::gasn_.ngasn[i] = ng;
5433 Magboltz::ratio_.frac[i] = 100 * fraction[i];
5434 }
5435
5436 // Call Magboltz internal setup routine.
5438
5439 // Calculate the max. energy in the table.
5440 if (e * m_temperature / (293.15 * m_pressure) > 15) {
5441 // If E/p > 15 start with 8 eV.
5442 Magboltz::inpt_.efinal = 8.;
5443 } else {
5444 Magboltz::inpt_.efinal = 0.5;
5445 }
5446 Magboltz::setp_.estart = Magboltz::inpt_.efinal / 50.;
5447
5448 long long ielow = 1;
5449 while (ielow == 1) {
5451 if (bmag == 0. || btheta == 0. || fabs(btheta) == Pi) {
5452 Magboltz::elimit_(&ielow);
5453 } else if (btheta == HalfPi) {
5454 Magboltz::elimitb_(&ielow);
5455 } else {
5456 Magboltz::elimitc_(&ielow);
5457 }
5458 if (ielow == 1) {
5459 // Increase the max. energy.
5460 Magboltz::inpt_.efinal *= sqrt(2.);
5461 Magboltz::setp_.estart = Magboltz::inpt_.efinal / 50.;
5462 }
5463 }
5464
5465 if (m_debug || verbose) Magboltz::prnter_();
5466
5467 // Run the Monte Carlo calculation.
5468 if (bmag == 0.) {
5470 } else if (btheta == 0. || btheta == Pi) {
5472 } else if (btheta == HalfPi) {
5474 } else {
5476 }
5477 if (m_debug || verbose) Magboltz::output_();
5478
5479 // If attachment or ionisation rate is greater than sstmin,
5480 // include spatial gradients in the solution.
5481 const double sstmin = 30.;
5482 const double epscale = 760. * m_temperature / (m_pressure * 293.15);
5483 double alpp = Magboltz::ctowns_.alpha * epscale;
5484 double attp = Magboltz::ctowns_.att * epscale;
5485 bool useSST = false;
5486 if (fabs(alpp - attp) > sstmin || alpp > sstmin || attp > sstmin) {
5487 useSST = true;
5488 if (bmag == 0.) {
5490 } else if (btheta == 0. || btheta == Pi) {
5492 } else if (btheta == HalfPi) {
5494 } else {
5496 }
5497 // Calculate the (effective) TOF Townsend coefficient.
5498 double alphapt = Magboltz::tofout_.ralpha;
5499 double etapt = Magboltz::tofout_.rattof;
5500 double fc1 =
5501 1.e5 * Magboltz::tofout_.tofwr / (2. * Magboltz::tofout_.tofdl);
5502 double fc2 = 1.e12 * (alphapt - etapt) / Magboltz::tofout_.tofdl;
5503 alphatof = fc1 - sqrt(fc1 * fc1 - fc2);
5504 }
5505 if (m_debug || verbose) Magboltz::output2_();
5506
5507 // Convert to cm / ns.
5508 vx = Magboltz::vel_.wx * 1.e-9;
5509 vxerr = Magboltz::velerr_.dwx;
5510 vy = Magboltz::vel_.wy * 1.e-9;
5511 vyerr = Magboltz::velerr_.dwy;
5512 vz = Magboltz::vel_.wz * 1.e-9;
5513 vzerr = Magboltz::velerr_.dwz;
5514
5515 dt = sqrt(0.2 * Magboltz::difvel_.diftr / vz) * 1.e-4;
5516 dterr = Magboltz::diferl_.dfter;
5517 dl = sqrt(0.2 * Magboltz::difvel_.difln / vz) * 1.e-4;
5518 dlerr = Magboltz::diferl_.dfler;
5519
5520 alpha = Magboltz::ctowns_.alpha;
5521 alphaerr = Magboltz::ctwner_.alper;
5522 eta = Magboltz::ctowns_.att;
5523 etaerr = Magboltz::ctwner_.atter;
5524
5525 // Print the results.
5526 if (m_debug) {
5527 std::cout << m_className << "::RunMagboltz:\n";
5528 std::cout << " Results: \n";
5529 std::cout << " Drift velocity along E: " << std::right
5530 << std::setw(10) << std::setprecision(6) << vz << " cm/ns +/- "
5531 << std::setprecision(2) << vzerr << "%\n";
5532 std::cout << " Drift velocity along Bt: " << std::right
5533 << std::setw(10) << std::setprecision(6) << vx << " cm/ns +/- "
5534 << std::setprecision(2) << vxerr << "%\n";
5535 std::cout << " Drift velocity along ExB: " << std::right
5536 << std::setw(10) << std::setprecision(6) << vy << " cm/ns +/- "
5537 << std::setprecision(2) << vyerr << "%\n";
5538 std::cout << " Longitudinal diffusion: " << std::right
5539 << std::setw(10) << std::setprecision(6) << dl << " cm1/2 +/- "
5540 << std::setprecision(2) << dlerr << "%\n";
5541 std::cout << " Transverse diffusion: " << std::right
5542 << std::setw(10) << std::setprecision(6) << dt << " cm1/2 +/- "
5543 << std::setprecision(2) << dterr << "%\n";
5544 if (useSST) {
5545 std::cout << " Townsend coefficient (SST): " << std::right
5546 << std::setw(10) << std::setprecision(6) << alpha
5547 << " cm-1 +/- " << std::setprecision(2) << alphaerr << "%\n";
5548 std::cout << " Attachment coefficient (SST): " << std::right
5549 << std::setw(10) << std::setprecision(6) << eta << " cm-1 +/- "
5550 << std::setprecision(2) << etaerr << "%\n";
5551 std::cout << " Eff. Townsend coefficient (TOF): " << std::right
5552 << std::setw(10) << std::setprecision(6) << alphatof
5553 << " cm-1\n";
5554 } else {
5555 std::cout << " Townsend coefficient: " << std::right
5556 << std::setw(10) << std::setprecision(6) << alpha
5557 << " cm-1 +/- " << std::setprecision(2) << alphaerr << "%\n";
5558 std::cout << " Attachment coefficient: " << std::right
5559 << std::setw(10) << std::setprecision(6) << eta << " cm-1 +/- "
5560 << std::setprecision(2) << etaerr << "%\n";
5561 }
5562 }
5563}
5564
5565void MediumMagboltz::GenerateGasTable(const int numColl, const bool verbose) {
5566
5567 // Set the reference pressure and temperature.
5570
5571 // Initialize the parameter arrays.
5580
5584 m_hasElectronDiffLong = true;
5586 m_hasElectronTownsend = true;
5588
5589 m_hasExcRates = false;
5590 tabExcRates.clear();
5591 excitationList.clear();
5592 nExcListElements = 0;
5593 m_hasIonRates = false;
5594 tabIonRates.clear();
5595 ionisationList.clear();
5596 nIonListElements = 0;
5597
5598 m_hasIonMobility = false;
5599 m_hasIonDissociation = false;
5600 m_hasIonDiffLong = false;
5601 m_hasIonDiffTrans = false;
5602
5603 // gasBits = "TFTTFTFTTTFFFFFF";
5604 // The version number is 11 because there are slight
5605 // differences between the way these gas files are written
5606 // and the ones from Garfield. This is mainly in the way
5607 // the gas tables are stored.
5608 // versionNumber = 11;
5609
5610 double vx = 0., vy = 0., vz = 0.;
5611 double difl = 0., dift = 0.;
5612 double alpha = 0., eta = 0.;
5613 double vxerr = 0., vyerr = 0., vzerr = 0.;
5614 double diflerr = 0., difterr = 0.;
5615 double alphaerr = 0., etaerr = 0.;
5616 double alphatof = 0.;
5617
5618 // Run through the grid of E- and B-fields and angles.
5619 for (unsigned int i = 0; i < m_nEfields; ++i) {
5620 for (unsigned int j = 0; j < m_nAngles; ++j) {
5621 for (unsigned int k = 0; k < m_nBfields; ++k) {
5622 if (m_debug) {
5623 std::cout << m_className << "::GenerateGasTable:\n";
5624 std::cout << " E = " << eFields[i] << " V/cm, B = " << bFields[k]
5625 << " T, angle: " << bAngles[j] << " rad\n";
5626 }
5627 RunMagboltz(eFields[i], bFields[k], bAngles[j], numColl, verbose, vx,
5628 vy, vz, difl, dift, alpha, eta, vxerr, vyerr, vzerr,
5629 diflerr, difterr, alphaerr, etaerr, alphatof);
5630 tabElectronVelocityE[j][k][i] = vz;
5631 tabElectronVelocityExB[j][k][i] = vy;
5632 tabElectronVelocityB[j][k][i] = vx;
5633 tabElectronDiffLong[j][k][i] = difl;
5634 tabElectronDiffTrans[j][k][i] = dift;
5635 if (alpha > 0.) {
5636 tabElectronTownsend[j][k][i] = log(alpha);
5637 tabTownsendNoPenning[j][k][i] = log(alpha);
5638 } else {
5639 tabElectronTownsend[j][k][i] = -30.;
5640 tabTownsendNoPenning[j][k][i] = -30.;
5641 }
5642 if (eta > 0.) {
5643 tabElectronAttachment[j][k][i] = log(eta);
5644 } else {
5645 tabElectronAttachment[j][k][i] = -30.;
5646 }
5647 }
5648 }
5649 }
5650}
5651}
DoubleAc cos(const DoubleAc &f)
Definition: DoubleAc.cpp:431
DoubleAc asin(const DoubleAc &f)
Definition: DoubleAc.cpp:468
DoubleAc pow(const DoubleAc &f, double p)
Definition: DoubleAc.cpp:336
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:313
DoubleAc sin(const DoubleAc &f)
Definition: DoubleAc.cpp:383
DoubleAc acos(const DoubleAc &f)
Definition: DoubleAc.cpp:488
DoubleAc exp(const DoubleAc &f)
Definition: DoubleAc.cpp:376
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:616
std::vector< ionListElement > ionisationList
Definition: MediumGas.hh:128
std::vector< std::vector< std::vector< std::vector< double > > > > tabIonRates
Definition: MediumGas.hh:110
bool GetGasName(const int gasnumber, const int version, std::string &gasname)
Definition: MediumGas.cc:2045
std::vector< std::vector< std::vector< double > > > tabTownsendNoPenning
Definition: MediumGas.hh:105
double lambdaPenningGas[m_nMaxGases]
Definition: MediumGas.hh:98
double lambdaPenningGlobal
Definition: MediumGas.hh:97
double fraction[m_nMaxGases]
Definition: MediumGas.hh:86
std::vector< std::vector< std::vector< std::vector< double > > > > tabExcRates
Definition: MediumGas.hh:109
std::string gas[m_nMaxGases]
Definition: MediumGas.hh:85
static const unsigned int m_nMaxGases
Definition: MediumGas.hh:82
double rPenningGas[m_nMaxGases]
Definition: MediumGas.hh:95
std::vector< excListElement > excitationList
Definition: MediumGas.hh:121
double GetNumberDensity() const
Definition: MediumGas.cc:261
int GetNumberOfPhotonCollisions() const
void SetExcitationScalingFactor(const double r, std::string gasname)
bool GetDeexcitationProduct(const int i, double &t, double &s, int &type, double &energy)
bool GetIonisationProduct(const int i, int &type, double &energy)
void EnablePenningTransfer(const double r, const double lambda)
void ComputeDeexcitation(int iLevel, int &fLevel)
double GetPhotonCollisionRate(const double &e)
void GenerateGasTable(const int numCollisions=10, const bool verbose=true)
bool SetMaxPhotonEnergy(const double e)
bool GetElectronCollision(const double e, int &type, int &level, double &e1, double &dx, double &dy, double &dz, int &nion, int &ndxc, int &band)
double GetElectronNullCollisionRate(const int band)
bool Initialise(const bool verbose=false)
bool GetLevel(const int i, int &ngas, int &type, std::string &descr, double &e)
bool SetMaxElectronEnergy(const double e)
int GetNumberOfElectronCollisions() const
void RunMagboltz(const double e, const double b, const double btheta, const int ncoll, bool verbose, double &vx, double &vy, double &vz, double &dl, double &dt, double &alpha, double &eta, double &vxerr, double &vyerr, double &vzerr, double &dlerr, double &dterr, double &alphaerr, double &etaerr, double &alphatof)
double GetElectronCollisionRate(const double e, const int band)
bool GetPhotonCollision(const double e, int &type, int &level, double &e1, double &ctheta, int &nsec, double &esec)
unsigned int m_nBfields
Definition: Medium.hh:323
bool m_microscopic
Definition: Medium.hh:309
double m_pressure
Definition: Medium.hh:295
bool m_hasElectronDiffTrans
Definition: Medium.hh:334
bool m_hasElectronTownsend
Definition: Medium.hh:335
std::vector< double > bFields
Definition: Medium.hh:327
std::vector< std::vector< std::vector< double > > > tabElectronVelocityB
Definition: Medium.hh:338
unsigned int m_nAngles
Definition: Medium.hh:324
bool m_hasElectronVelocityB
Definition: Medium.hh:333
std::vector< double > eFields
Definition: Medium.hh:326
std::vector< std::vector< std::vector< double > > > tabElectronVelocityE
Definition: Medium.hh:336
std::vector< double > bAngles
Definition: Medium.hh:328
std::vector< std::vector< std::vector< double > > > tabElectronDiffLong
Definition: Medium.hh:339
std::vector< std::vector< std::vector< double > > > tabElectronAttachment
Definition: Medium.hh:342
virtual void EnableDrift()
Definition: Medium.hh:52
unsigned int m_nEfields
Definition: Medium.hh:322
bool m_hasElectronVelocityExB
Definition: Medium.hh:333
bool m_hasIonDiffTrans
Definition: Medium.hh:363
bool m_hasIonMobility
Definition: Medium.hh:362
bool m_hasElectronDiffLong
Definition: Medium.hh:334
virtual void EnablePrimaryIonisation()
Definition: Medium.hh:54
void InitParamArrays(const unsigned int &eRes, const unsigned int &bRes, const unsigned int &aRes, std::vector< std::vector< std::vector< double > > > &tab, const double &val)
Definition: Medium.cc:2772
unsigned int m_nComponents
Definition: Medium.hh:299
std::string m_className
Definition: Medium.hh:284
bool m_hasIonDissociation
Definition: Medium.hh:364
bool m_hasIonDiffLong
Definition: Medium.hh:363
bool m_isChanged
Definition: Medium.hh:316
bool m_hasElectronVelocityE
Definition: Medium.hh:333
std::vector< std::vector< std::vector< double > > > tabElectronTownsend
Definition: Medium.hh:341
bool m_hasElectronAttachment
Definition: Medium.hh:335
double m_temperature
Definition: Medium.hh:293
std::vector< std::vector< std::vector< double > > > tabElectronDiffTrans
Definition: Medium.hh:340
std::vector< std::vector< std::vector< double > > > tabElectronVelocityExB
Definition: Medium.hh:337
void gasmix_(long long *ngs, double *q, double *qin, long long *nin, double *e, double *ei, char *name, double *virl, double *eb, double *peqel, double *peqin, double *penfra, long long *kel, long long *kin, double *qion, double *peqion, double *eion, long long *nion, char scrpt[260][50])
struct Garfield::Magboltz::@5 ratio_
struct Garfield::Magboltz::@12 ctowns_
void elimitc_(long long *ielow)
struct Garfield::Magboltz::@13 ctwner_
struct Garfield::Magboltz::@4 gasn_
struct Garfield::Magboltz::@0 bfld_
struct Garfield::Magboltz::@7 velerr_
struct Garfield::Magboltz::@2 setp_
void elimit_(long long *ielow)
struct Garfield::Magboltz::@1 inpt_
void elimitb_(long long *ielow)
struct Garfield::Magboltz::@3 cnsts_
struct Garfield::Magboltz::@14 tofout_
struct Garfield::Magboltz::@10 difvel_
struct Garfield::Magboltz::@6 vel_
struct Garfield::Magboltz::@11 diferl_
double RndmUniform()
Definition: Random.hh:16
double RndmVoigt(const double mu, const double sigma, const double gamma)
Definition: Random.hh:67
double RndmUniformPos()
Definition: Random.hh:19