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