phystota

eduPIC_DRR_v1.4 - stable

Jun 2nd, 2025
27
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 74.36 KB | None | 0 0
  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cstdbool>
  5. #include <cmath>
  6. #include <ctime>
  7. #include <random>
  8. #include <vector>
  9. #include <string>
  10. #include <fstream>
  11. #include <sstream>
  12. #include <algorithm>    
  13. #include <stdexcept>
  14. #include <iostream>
  15. #include <iomanip>
  16.  
  17. using namespace::std;
  18.  
  19. // constants
  20.  
  21. const double     PI             = 3.141592653589793;          // mathematical constant Pi
  22. const double     TWO_PI         = 2.0 * PI;                   // two times Pi
  23. const double     E_CHARGE       = 1.60217662e-19;             // electron charge [C]
  24. const double     EV_TO_J        = E_CHARGE;                   // eV <-> Joule conversion factor
  25. const double     E_MASS         = 9.109e-31;                  // mass of electron [kg]
  26. const double     HE_MASS        = 6.67e-27;                   // mass of He atom [kg]
  27. const double     MU_HEHE        = HE_MASS / 2.0;              // reduced mass of two He atoms [kg]
  28. const double     K_BOLTZMANN    = 1.38064852e-23;             // Boltzmann's constant [J/K]
  29. const double     EPSILON0       = 8.85418781e-12;             // permittivity of free space [F/m]
  30.  
  31.  
  32. // simulation parameters
  33.  
  34. const int        N_G            = 501;                        // number of grid points
  35. const int        N_T            = 2000;                        // time steps within an RF period
  36.  
  37.  
  38. const double     FREQUENCY      = 13.56e6;                    // driving frequency [Hz]
  39. const double     VOLTAGE        = 350.0;                      // voltage amplitude [V]
  40. const double     L              = 0.04;                      // electrode gap [m]
  41. const double     PRESSURE       = 13.3322;              // gas pressure [Pa] // n*k*T to match Turner's case
  42. const double     T_neutral      = 300.0;                      // background gas temperature [K] (also ion temperature)
  43. const double     T_electron     = 30000.0;                    // initial electron temperatutre [K]
  44. const double     WEIGHT         = 41875.0;                  // weight of superparticles
  45. const double     ELECTRODE_AREA = 1.6e-4;                     // (fictive) electrode area [m^2]
  46. const int        N_INIT         = 65536;                      // number of initial electrons and ions
  47.  
  48. // additional (derived) constants
  49.  
  50. const double     PERIOD         = 1.0 / FREQUENCY;                              // RF period length [s]
  51. const double     DT_E           = PERIOD / (double)(N_T);                       // electron time step [s]
  52. const int        N_SUB          = 5;                                            // ions move only in these cycles (subcycling)
  53. const int        N_avg          = 10;                                            // number of cycles to average rates --- Artem
  54.       int        counter        = -1;                                            // cycles since update of rates --- Artem
  55. const double     DT_I           = N_SUB * DT_E;                                 // ion time step [s]
  56. const double     DX             = L / (double)(N_G - 1);                        // spatial grid division [m]
  57. const double     INV_DX         = 1.0 / DX;                                     // inverse of spatial grid size [1/m]
  58. const double     GAS_DENSITY    = PRESSURE / (K_BOLTZMANN * T_neutral);         // background gas density [1/m^3]
  59. const double     OMEGA          = TWO_PI * FREQUENCY;                           // angular frequency [rad/s]
  60.  
  61. const double     Diff_coeff     = 8.992E-6*pow(T_neutral,1.5)/(PRESSURE/133.3); // diffusion coefficient for metastable states
  62.  
  63. // electron and ion cross sections
  64.  
  65. const int        N_CS           = 8;                          // total number of processes / cross sections
  66. const int        E_ELA          = 0;                          // process identifier: electron/elastic
  67. const int        E_EXC_1        = 1;                          // process identifier: electron/excitation1
  68. const int        E_EXC_2        = 2;                          // process identifier: electron/excitation1
  69. const int        E_ION          = 3;                          // process identifier: electron/ionization
  70. const int        I_ISO          = 4;                          // process identifier: ion/elastic/isotropic
  71. const int        I_BACK         = 5;                          // process identifier: ion/elastic/backscattering
  72.  
  73. const int        E_SUPER_1      = 6;                          // triplet excitation - Artem
  74. const int        E_SUPER_2      = 7;                          // singlet excitation - Artem
  75.  
  76. const double     E_EXC_TH_1     = 19.82;                      // electron impact excitation threshold [eV]
  77. const double     E_EXC_TH_2     = 20.61;                      // electron impact excitation threshold [eV]
  78. const double     E_ION_TH       = 24.587;                     // electron impact ionization threshold [eV]
  79. const int        CS_RANGES      = 1000000;                    // number of entries in cross section arrays
  80. const double     DE_CS          = 0.001;                      // energy division in cross section arrays [eV]
  81. typedef float    cross_section[CS_RANGES];                    // cross section array
  82. cross_section    sigma[N_CS];                                 // set of cross section arrays
  83. cross_section    sigma_tot_e;                                 // total macroscopic cross section of electrons
  84. cross_section    sigma_tot_i;                                 // total macroscopic cross section of ions
  85.  
  86. double nu_avg;                                                // average nu for electrons thorugh 1 cycle
  87.  
  88. // particle coordinates
  89.  
  90. const int        MAX_N_P = 10000000;                           // maximum number of particles (electrons / ions)
  91. typedef double   particle_vector[MAX_N_P];                    // array for particle properties
  92. int              N_e = 0;                                     // number of electrons
  93. int              N_i = 0;                                     // number of ions
  94. int              N_e1 = 0;                                    // number of singlet excited states
  95. int              N_e2 = 0;                                    // number of triplet excited states
  96. particle_vector  x_e, vx_e, vy_e, vz_e;                       // coordinates of electrons (one spatial, three velocity components)
  97. particle_vector  x_i, vx_i, vy_i, vz_i;                       // coordinates of ions (one spatial, three velocity components)
  98.  
  99.  
  100.  
  101.  
  102. typedef double   xvector[N_G];                                // array for quantities defined at gird points
  103. xvector          efield,pot;                                  // electric field and potential
  104. xvector          e_density,i_density;                         // electron and ion densities
  105. xvector          cumul_e_density,cumul_i_density;             // cumulative densities
  106.  
  107. //excited states handling
  108. xvector e1_density;
  109. xvector e2_density;
  110. xvector sum_electron_density; xvector avg_electron_density;
  111.  
  112. xvector sum_rate1f = {0.0}; xvector sum_rate1b = {0.0}; xvector sum_rate2f = {0.0}; xvector sum_rate2b = {0.0};
  113.  
  114. xvector avg_rate1f = {0.0}; xvector avg_rate1b = {0.0}; xvector avg_rate2f = {0.0}; xvector avg_rate2b = {0.0};
  115.  
  116.                                        // array for Triplet excitation rates!!! Artem
  117. xvector S1 = {0.0};
  118. xvector S2 = {0.0};                                           // source terms for DRR module -- Artem
  119.  
  120. typedef unsigned long long int Ullong;                        // compact name for 64 bit unsigned integer
  121. Ullong       N_e_abs_pow  = 0;                                // counter for electrons absorbed at the powered electrode
  122. Ullong       N_e_abs_gnd  = 0;                                // counter for electrons absorbed at the grounded electrode
  123. Ullong       N_i_abs_pow  = 0;                                // counter for ions absorbed at the powered electrode
  124. Ullong       N_i_abs_gnd  = 0;                                // counter for ions absorbed at the grounded electrode
  125.  
  126. // electron energy probability function
  127.  
  128. const int    N_EEPF  = 2000;                                 // number of energy bins in Electron Energy Probability Function (EEPF)
  129. const double DE_EEPF = 0.05;                                 // resolution of EEPF [eV]
  130. typedef double eepf_vector[N_EEPF];                          // array for EEPF
  131. eepf_vector eepf     = {0.0};                                // time integrated EEPF in the center of the plasma
  132.  
  133. // ion flux-energy distributions
  134.  
  135. const int    N_IFED   = 200;                                 // number of energy bins in Ion Flux-Energy Distributions (IFEDs)
  136. const double DE_IFED  = 1.0;                                 // resolution of IFEDs [eV]
  137. typedef int  ifed_vector[N_IFED];                            // array for IFEDs
  138. ifed_vector  ifed_pow = {0};                                 // IFED at the powered electrode
  139. ifed_vector  ifed_gnd = {0};                                 // IFED at the grounded electrode
  140. double       mean_i_energy_pow;                              // mean ion energy at the powered electrode
  141. double       mean_i_energy_gnd;                              // mean ion energy at the grounded electrode
  142.  
  143. // spatio-temporal (XT) distributions
  144.  
  145. const int N_BIN                     = 20;                    // number of time steps binned for the XT distributions
  146. const int N_XT                      = N_T / N_BIN;           // number of spatial bins for the XT distributions
  147. typedef double xt_distr[N_G][N_XT];                          // array for XT distributions (decimal numbers)
  148. xt_distr pot_xt                     = {0.0};                 // XT distribution of the potential
  149. xt_distr efield_xt                  = {0.0};                 // XT distribution of the electric field
  150. xt_distr ne_xt                      = {0.0};                 // XT distribution of the electron density
  151. xt_distr ni_xt                      = {0.0};                 // XT distribution of the ion density
  152. xt_distr ue_xt                      = {0.0};                 // XT distribution of the mean electron velocity
  153. xt_distr ui_xt                      = {0.0};                 // XT distribution of the mean ion velocity
  154. xt_distr je_xt                      = {0.0};                 // XT distribution of the electron current density
  155. xt_distr ji_xt                      = {0.0};                 // XT distribution of the ion current density
  156. xt_distr powere_xt                  = {0.0};                 // XT distribution of the electron powering (power absorption) rate
  157. xt_distr poweri_xt                  = {0.0};                 // XT distribution of the ion powering (power absorption) rate
  158. xt_distr meanee_xt                  = {0.0};                 // XT distribution of the mean electron energy
  159. xt_distr meanei_xt                  = {0.0};                 // XT distribution of the mean ion energy
  160. xt_distr counter_e_xt               = {0.0};                 // XT counter for electron properties
  161. xt_distr counter_i_xt               = {0.0};                 // XT counter for ion properties
  162. xt_distr ioniz_rate_xt              = {0.0};                 // XT distribution of the ionisation rate
  163.  
  164. xt_distr e1_xt                      = {0.0};                 // XT distribution of triplet excited states density - Artem
  165. xt_distr e2_xt                      = {0.0};                 // XT distribution of singlet excited states density - Artem
  166.  
  167. double   mean_energy_accu_center    = 0;                     // mean electron energy accumulator in the center of the gap
  168. Ullong   mean_energy_counter_center = 0;                     // mean electron energy counter in the center of the gap
  169. Ullong   N_e_coll                   = 0;                     // counter for electron collisions
  170. Ullong   N_i_coll                   = 0;                     // counter for ion collisions
  171. double   Time;                                               // total simulated time (from the beginning of the simulation)
  172. int      cycle,no_of_cycles,cycles_done;                     // current cycle and total cycles in the run, cycles completed
  173. int      arg1;                                               // used for reading command line arguments
  174. char     st0[80];                                            // used for reading command line arguments
  175. FILE     *datafile;                                          // used for saving data
  176. bool     measurement_mode;                                   // flag that controls measurements and data saving
  177.  
  178. const double gamma_i                = 0.3;                   // yielding coefficient for ions bombarding the surface
  179. const double gamma_m                = 0.3;                   // yielding coefficient for metastables bombarding the surface
  180. const double gamma_p                = -10.0;                   // yielding coefficient for photons bombarding the surface
  181. const double gamma_k                = 0.5;                     // recombination coefficient  
  182. const double r                      = 0.7;                   // probabilty for the electron to reflect at the surface
  183. const double T_SEE                  = 300;                   // initial temperature of SEE electrons [K]
  184.  
  185.  
  186. //---------------------------------------------------------------------------//
  187. // C++ Mersenne Twister 19937 generator                                      //
  188. // R01(MTgen) will genarate uniform distribution over [0,1) interval         //
  189. // RMB(MTgen) will generate Maxwell-Boltzmann distribution (of gas atoms)    //
  190. //---------------------------------------------------------------------------//
  191.  
  192. std::random_device rd{};
  193. std::mt19937 MTgen(rd());
  194. std::uniform_real_distribution<> R01(0.0, 1.0);
  195. std::normal_distribution<> RMB_n(0.0,sqrt(K_BOLTZMANN * T_neutral / HE_MASS));
  196. std::normal_distribution<> RMB_e(0.0,sqrt(K_BOLTZMANN * T_electron / E_MASS));
  197. std::normal_distribution<> RMB_SEE(0.0,sqrt(K_BOLTZMANN * T_SEE / E_MASS));
  198.  
  199. //----------------------------------------------------------------------------//
  200. //  electron cross sections: A V Phelps & Z Lj Petrovic, PSST 8 R21 (1999)    //
  201. //----------------------------------------------------------------------------//
  202.  
  203. class CSInterpolator {
  204. public:
  205.   // load "filename" which must have two whitespace‐separated columns:
  206.   //    energy (eV)    cross_section (in m^2 or cm^2 as you prefer)
  207.   CSInterpolator(const std::string &filename) {
  208.     std::ifstream in(filename);
  209.     if (!in) throw std::runtime_error("CSInterpolator: cannot open " + filename);
  210.     double E, sigma;
  211.     std::string line;
  212.     while (std::getline(in, line)) {
  213.       std::istringstream iss(line);
  214.       if (iss >> E >> sigma) {
  215.         E_pts_.push_back(E);
  216.         sigma_pts_.push_back(sigma);
  217.       }
  218.     }
  219.     if (E_pts_.size()<2)
  220.       throw std::runtime_error("CSInterpolator: need at least two data points in " + filename);
  221.   }
  222.  
  223.   // return σ(E) by simple linear interpolation (clamped to end‐points)
  224.   double operator()(double E) const {
  225.     auto it = std::lower_bound(E_pts_.begin(), E_pts_.end(), E);
  226.     if (it == E_pts_.begin()) {
  227. //        std::cerr << "Warning: E="<<E<<" below data range, clamping to "<< 0.0 <<"\n";
  228.         return 0.0;
  229.     }  
  230.     if (it == E_pts_.end()){
  231. //        std::cerr << "Warning: E="<<E<<" above data range, clamping to "<< sigma_pts_.back() <<"\n";
  232.         return sigma_pts_.back();
  233.     }    
  234.     size_t idx = (it - E_pts_.begin());
  235.     double E1 = E_pts_[idx-1], E2 = E_pts_[idx];
  236.     double s1 = sigma_pts_[idx-1], s2 = sigma_pts_[idx];
  237.     // linear interp
  238.     return s1 + (s2 - s1) * (E - E1)/(E2 - E1);
  239.   }
  240.  
  241. private:
  242.   std::vector<double> E_pts_, sigma_pts_;
  243. };
  244.  
  245. void set_electron_cross_sections_ar(void){
  246.     int    i;
  247.     double en,qmel,qexc_1,qexc_2,qion;
  248.    
  249.     printf(">> eduPIC: Setting e- / He cross sections\n");
  250.  
  251.     // load your four datafiles (make sure these names match your files!)
  252.     CSInterpolator cs_ela  ("CS/He_electron_elastic.dat");   // two‐col: E σ_ela
  253.     CSInterpolator cs_exc1 ("CS/He_electron_exc1.dat");      // two‐col: E σ_exc1
  254.     CSInterpolator cs_exc2 ("CS/He_electron_exc2.dat");      // two‐col: E σ_exc2
  255.     CSInterpolator cs_ion  ("CS/He_electron_ionization.dat");// two‐col: E σ_ion
  256.  
  257.     for(int i=0; i<CS_RANGES; i++){
  258.         // your energy grid
  259.         double en = (i==0 ? DE_CS : DE_CS * i);
  260.  
  261.         // interpolate
  262.         sigma[E_ELA][i]   = cs_ela(en);
  263.         sigma[E_EXC_1][i] = cs_exc1(en);
  264.         sigma[E_EXC_2][i] = cs_exc2(en);
  265.         sigma[E_ION][i]   = cs_ion(en);
  266.  
  267.         // Superelastic for triplet (E_SUPER_1)
  268.         double en_plus_1 = en + E_EXC_TH_1;
  269.         int idx1 = en_plus_1 / DE_CS;
  270.         if (idx1 < CS_RANGES && en > 0) {
  271.             sigma[E_SUPER_1][i] = (1.0 / 3.0) * (en_plus_1 / en) * sigma[E_EXC_1][idx1];
  272.         } else {
  273.             sigma[E_SUPER_1][i] = 0.0;
  274.         }        
  275.  
  276.         // Superelastic for singlet (E_SUPER_2)
  277.         double en_plus_2 = en + E_EXC_TH_2;
  278.         int idx2 = en_plus_2 / DE_CS;
  279.         if (idx2 < CS_RANGES && en > 0) {
  280.             sigma[E_SUPER_2][i] = (1.0 / 1.0) * (en_plus_2 / en) * sigma[E_EXC_2][idx2];
  281.         } else {
  282.             sigma[E_SUPER_2][i] = 0.0;
  283.         }        
  284.     }
  285.  
  286.     // for(int i=0; i<CS_RANGES; i++){
  287.     //     // your energy grid
  288.     //     double en = (i==0 ? DE_CS : DE_CS * i);
  289.  
  290.     //     // Superelastic for triplet (E_SUPER_1)
  291.     //     double en_plus_1 = en + E_EXC_TH_1;
  292.     //     int idx1 = en_plus_1 / DE_CS;
  293.     //     if (idx1 < CS_RANGES && en > 0) {
  294.     //         sigma[E_SUPER_1][i] = (1.0 / 3.0) * (en_plus_1 / en) * sigma[E_EXC_1][idx1];
  295.     //     } else {
  296.     //         sigma[E_SUPER_1][i] = 0.0;
  297.     //     }        
  298.  
  299.     //     // Superelastic for singlet (E_SUPER_2)
  300.     //     double en_plus_2 = en + E_EXC_TH_2;
  301.     //     int idx2 = en_plus_2 / DE_CS;
  302.     //     if (idx2 < CS_RANGES && en > 0) {
  303.     //         sigma[E_SUPER_2][i] = (1.0 / 1.0) * (en_plus_2 / en) * sigma[E_EXC_2][idx2];
  304.     //     } else {
  305.     //         sigma[E_SUPER_2][i] = 0.0;
  306.     //     }        
  307.     // }    
  308. }
  309.  
  310. //------------------------------------------------------------------------------//
  311. //  ion cross sections: A. V. Phelps, J. Appl. Phys. 76, 747 (1994)             //
  312. //------------------------------------------------------------------------------//
  313.  
  314. void set_ion_cross_sections_ar(void){
  315.     int    i;
  316.     double e_com,e_lab,qmom,qback,qiso;
  317.    
  318.     printf(">> eduPIC: Setting He+ / He cross sections\n");
  319.     for(i=0; i<CS_RANGES; i++){
  320.         if (i == 0) {e_com = DE_CS;} else {e_com = DE_CS * i;}             // ion energy in the center of mass frame of reference
  321.         e_lab = 2.0 * e_com;                                               // ion energy in the laboratory frame of reference
  322.         qiso  = 7.63 *pow(10,-20) * pow(e_com, -0.5);
  323.         qback = 1.0 * pow(10,-19) * pow( (e_com/1000.0), -0.15 ) * pow( (1.0 + e_com/1000.0), -0.25 ) * pow( (1.0 + 5.0/e_com), -0.15 );
  324.         sigma[I_ISO][i]  = qiso;             // cross section for He+ / He isotropic part of elastic scattering
  325.         sigma[I_BACK][i] = qback;            // cross section for He+ / He backward elastic scattering
  326.     }
  327. }
  328.  
  329. //----------------------------------------------------------------------//
  330. //  calculation of total cross sections for electrons and ions          //
  331. //----------------------------------------------------------------------//
  332.  
  333. void calc_total_cross_sections(void){
  334.     int i;
  335.    
  336.     for(i=0; i<CS_RANGES; i++){
  337.         sigma_tot_e[i] = (sigma[E_ELA][i] + sigma[E_EXC_1][i] + sigma[E_EXC_2][i] + sigma[E_ION][i]) * GAS_DENSITY;   // total macroscopic cross section of electrons
  338.         sigma_tot_i[i] = (sigma[I_ISO][i] + sigma[I_BACK][i]) * GAS_DENSITY;                    // total macroscopic cross section of ions
  339.     }
  340. }
  341.  
  342. //----------------------------------------------------------------------//
  343. //  test of cross sections for electrons and ions                       //
  344. //----------------------------------------------------------------------//
  345.  
  346. void test_cross_sections(void){
  347.     FILE  * f;
  348.     int   i,j;
  349.    
  350.     f = fopen("cross_sections.dat","w");        // cross sections saved in data file: cross_sections.dat
  351.     for(i=0; i<CS_RANGES; i++){
  352.         fprintf(f,"%12.4f ",i*DE_CS);
  353.         for(j=0; j<N_CS; j++) fprintf(f,"%14e ",sigma[j][i]);
  354.         fprintf(f,"\n");
  355.     }
  356.     fclose(f);
  357. }
  358.  
  359. //---------------------------------------------------------------------//
  360. // find upper limit of collision frequencies                           //
  361. //---------------------------------------------------------------------//
  362.  
  363. double max_electron_coll_freq (void){
  364.     int i;
  365.     double e,v,nu,nu_max;
  366.     nu_max = 0;
  367.     for(i=0; i<CS_RANGES; i++){
  368.         e  = i * DE_CS;
  369.         v  = sqrt(2.0 * e * EV_TO_J / E_MASS);
  370.         nu = v * sigma_tot_e[i];
  371.         if (nu > nu_max) {nu_max = nu;}
  372.     }
  373.     return nu_max;
  374. }
  375.  
  376. double max_ion_coll_freq (void){
  377.     int i;
  378.     double e,g,nu,nu_max;
  379.     nu_max = 0;
  380.     for(i=0; i<CS_RANGES; i++){
  381.         e  = i * DE_CS;
  382.         g  = sqrt(2.0 * e * EV_TO_J / MU_HEHE);
  383.         nu = g * sigma_tot_i[i];
  384.         if (nu > nu_max) nu_max = nu;
  385.     }
  386.     return nu_max;
  387. }
  388.  
  389. //----------------------------------------------------------------------//
  390. // initialization of the simulation by placing a given number of        //
  391. // electrons and ions at random positions between the electrodes        //
  392. //----------------------------------------------------------------------//
  393.  
  394. // initialization of excited states distribtuion, assuming Maxwellian-Boltzmann balance -- Artem
  395. std::pair<double, double> init_excited_distr() {
  396.     double part_ground = 1.0*exp(-0.0/T_neutral); // partition function for ground state
  397.     double part_triplet = 3.0*exp(-E_EXC_TH_1*EV_TO_J/(K_BOLTZMANN*T_neutral)); // partition function for triplet excited state
  398.     double part_singlet = 1.0*exp(-E_EXC_TH_2*EV_TO_J/(K_BOLTZMANN*T_neutral)); // partition function for singlet excited state
  399.     double part_func_total = part_ground + part_triplet + part_singlet; // total partition function
  400.     double n_triplet = ((part_triplet/part_func_total)*GAS_DENSITY); // denisty population of tripet state
  401.     double n_singlet = ((part_singlet/part_func_total)*GAS_DENSITY); // density population of singlet state
  402.  
  403.     return {n_triplet, n_singlet};
  404. }
  405.  
  406. void print_excitation_densities(void) {
  407.     double total_e1 = 0.0, total_e2 = 0.0;
  408.     const double cell_volume = ELECTRODE_AREA * DX;
  409.    
  410.     // Sum densities across all grid cells
  411.     for (int p = 0; p < N_G; p++) {
  412.         total_e1 += e1_density[p];  // triplet state density
  413.         total_e2 += e2_density[p];  // singlet state density
  414.     }
  415.     printf("average Triplet SP = %8.2e | average Singlet SP = %8.2e\n", total_e1/N_G, total_e2/N_G);
  416. }
  417.  
  418. void init(int nseed){
  419.     int i;
  420.    
  421.     for (i=0; i<nseed; i++){
  422.         x_e[i]  = L * R01(MTgen);                                                   // initial random position of the electron
  423.         vx_e[i] = RMB_e(MTgen); vy_e[i] = RMB_e(MTgen); vz_e[i] = RMB_e(MTgen);     // initial velocity components of the electron
  424.         x_i[i]  = L * R01(MTgen);                                                   // initial random position of the ion
  425.         vx_i[i] = RMB_n(MTgen); vy_i[i] = RMB_n(MTgen); vz_i[i] = RMB_n(MTgen);     // initial velocity components of the ion
  426.     }
  427.     N_e = nseed;    // initial number of electrons
  428.     N_i = nseed;    // initial number of ions
  429.  
  430.     double n_min = 1e-15 * GAS_DENSITY;
  431.     auto exc = init_excited_distr();
  432.     for (int p = 0; p < N_G; p++) {
  433.         e1_density[p] = exc.first;
  434.         e2_density[p] = exc.second;
  435.     }
  436. }
  437.  
  438. //----------------------------------------------------------------------//
  439. // e / He collision  (cold gas approximation)                           //
  440. //----------------------------------------------------------------------//
  441.  
  442. void collision_electron (double xe, double *vxe, double *vye, double *vze, int eindex){
  443.     const double F1 = E_MASS  / (E_MASS + HE_MASS);
  444.     const double F2 = HE_MASS / (E_MASS + HE_MASS);
  445.     double t0,t1,t2,t3,t4,t5,rnd;
  446.     double g,g2,gx,gy,gz,wx,wy,wz,theta,phi;
  447.     double chi,eta,chi2,eta2,sc,cc,se,ce,st,ct,sp,cp,energy,e_sc,e_ej;
  448.  
  449.     // - Artem
  450.     // Determine cell p where the electron is
  451.     double c0 = xe * INV_DX;
  452.     int p = std::max(0, std::min(N_G - 1, static_cast<int>(c0)));
  453.  
  454.     // Local densities -- Artem
  455.     double e1_dens = e1_density[p];
  456.     double e2_dens = e2_density[p];
  457.     double ground_dens = GAS_DENSITY - e1_dens - e2_dens;    
  458.  
  459.    
  460.     // calculate relative velocity before collision & velocity of the centre of mass
  461.    
  462.     gx = (*vxe);
  463.     gy = (*vye);
  464.     gz = (*vze);
  465.     g  = sqrt(gx * gx + gy * gy + gz * gz);
  466.     wx = F1 * (*vxe);
  467.     wy = F1 * (*vye);
  468.     wz = F1 * (*vze);
  469.    
  470.     // find Euler angles
  471.    
  472.     if (gx == 0) {theta = 0.5 * PI;}
  473.     else {theta = atan2(sqrt(gy * gy + gz * gz),gx);}
  474.     if (gy == 0) {
  475.         if (gz > 0){phi = 0.5 * PI;} else {phi = - 0.5 * PI;}
  476.     } else {phi = atan2(gz, gy);}
  477.     st  = sin(theta);
  478.     ct  = cos(theta);
  479.     sp  = sin(phi);
  480.     cp  = cos(phi);
  481.    
  482.     // choose the type of collision based on the cross sections
  483.     // take into account energy loss in inelastic collisions
  484.     // generate scattering and azimuth angles
  485.     // in case of ionization handle the 'new' electron
  486.    
  487.     t0   =      sigma[E_ELA][eindex] * ground_dens;
  488.     t1   = t0 + sigma[E_EXC_1][eindex] * ground_dens;
  489.     t2   = t1 + sigma[E_EXC_2][eindex] * ground_dens;
  490.     t3   = t2 + sigma[E_ION][eindex] * ground_dens;
  491.     t4   = t3 + sigma[E_SUPER_1][eindex]  * e1_dens;   // account for superelastic triplet - Artem
  492.     t5   = t4 + sigma[E_SUPER_2][eindex] * e2_dens;   // account for superelastic singlet- Artem
  493.  
  494.     rnd  = R01(MTgen);
  495.     if (rnd < (t0/t5)){                              // elastic scattering
  496.         chi = acos(1.0 - 2.0 * R01(MTgen));          // isotropic scattering
  497.         eta = TWO_PI * R01(MTgen);                   // azimuthal angle
  498.  
  499.     } else if (rnd < (t1/t5)){                       // excitation 1 (triplet)
  500.         energy = 0.5 * E_MASS * g * g;               // electron energy
  501.         energy = fabs(energy - E_EXC_TH_1 * EV_TO_J);  // subtract energy loss for excitation
  502.         g   = sqrt(2.0 * energy / E_MASS);           // relative velocity after energy loss
  503.         chi = acos(1.0 - 2.0 * R01(MTgen));          // isotropic scattering
  504.         eta = TWO_PI * R01(MTgen);                   // azimuthal angle
  505.  
  506.         //add new triplet excited He atom density to this grid point, sample velocities from Maxwellian distribution - Artem
  507.         //no need if we calculate rates and densities outside
  508. //        e1_density[p] += WEIGHT / (ELECTRODE_AREA * DX);
  509.  
  510.     } else if (rnd < (t2/t5)){                       // excitation 2 (singlet)
  511.         energy = 0.5 * E_MASS * g * g;               // electron energy
  512.         energy = fabs(energy - E_EXC_TH_2 * EV_TO_J);  // subtract energy loss for excitation
  513.         g   = sqrt(2.0 * energy / E_MASS);           // relative velocity after energy loss
  514.         chi = acos(1.0 - 2.0 * R01(MTgen));          // isotropic scattering
  515.         eta = TWO_PI * R01(MTgen);                   // azimuthal angle    
  516.  
  517.         //add new singet excited He atom, sample velocities from Maxwellian distribution - Artem
  518.         //no need if we calculate rates and densities outside
  519. //        e2_density[p] += WEIGHT / (ELECTRODE_AREA * DX);
  520.  
  521.     } else if (rnd < (t3/t5)) {                                         // ionization
  522.         energy = 0.5 * E_MASS * g * g;               // electron energy
  523.         energy = fabs(energy - E_ION_TH * EV_TO_J);  // subtract energy loss of ionization
  524.         // e_ej  = 10.0 * tan(R01(MTgen) * atan(energy/EV_TO_J / 20.0)) * EV_TO_J; // energy of the ejected electron
  525.         // e_sc = fabs(energy - e_ej);                  // energy of scattered electron after the collision
  526.         e_ej = 0.5*energy;                          // energy of the ejected electron
  527.         e_sc = fabs(energy - e_ej);                  // energy of scattered electron after the collision        
  528.         g    = sqrt(2.0 * e_sc / E_MASS);            // relative velocity of scattered electron
  529.         g2   = sqrt(2.0 * e_ej / E_MASS);            // relative velocity of ejected electron
  530.         // chi  = acos(sqrt(e_sc / energy));            // scattering angle for scattered electron
  531.         // chi2 = acos(sqrt(e_ej / energy));            // scattering angle for ejected electrons
  532.         chi = acos(1.0 - 2.0 * R01(MTgen));          // isotropic scattering for scattered electron (as in Turner's case)
  533.         chi2 = acos(1.0 - 2.0 * R01(MTgen));          // isotropic scattering for ejected electrons (as in Turner's case)
  534.         eta  = TWO_PI * R01(MTgen);                  // azimuthal angle for scattered electron
  535.         eta2 = eta + PI;                             // azimuthal angle for ejected electron
  536.         sc  = sin(chi2);
  537.         cc  = cos(chi2);
  538.         se  = sin(eta2);
  539.         ce  = cos(eta2);
  540.         gx  = g2 * (ct * cc - st * sc * ce);
  541.         gy  = g2 * (st * cp * cc + ct * cp * sc * ce - sp * sc * se);
  542.         gz  = g2 * (st * sp * cc + ct * sp * sc * ce + cp * sc * se);
  543.         x_e[N_e]  = xe;                              // add new electron
  544.         vx_e[N_e] = wx + F2 * gx;
  545.         vy_e[N_e] = wy + F2 * gy;
  546.         vz_e[N_e] = wz + F2 * gz;
  547.         N_e++;
  548.         x_i[N_i]  = xe;                              // add new ion
  549.         vx_i[N_i] = RMB_n(MTgen);                      // velocity is sampled from background thermal distribution
  550.         vy_i[N_i] = RMB_n(MTgen);
  551.         vz_i[N_i] = RMB_n(MTgen);
  552.         N_i++;
  553.     }
  554.      else if (rnd < (t4/t5)) {                      // accounting for superelastic collisions - triplet - Artem
  555.         energy = 0.5 * E_MASS * g * g;               // electron energy
  556.         energy = fabs(energy + E_EXC_TH_1 * EV_TO_J);  // add energy for deexcitation
  557.         g   = sqrt(2.0 * energy / E_MASS);           // relative velocity after energy loss
  558.         chi = acos(1.0 - 2.0 * R01(MTgen));          // isotropic scattering
  559.         eta = TWO_PI * R01(MTgen);                   // azimuthal angle    
  560.  
  561.         //substract  excited He atom density from the grid point - Artem
  562.         //no need if we calculate rates and densities outside
  563. //        e1_density[p] = std::max(e1_density[p] - WEIGHT / (ELECTRODE_AREA * DX), 0.0);
  564.    
  565.     } else {                                         // account for supeelastic collision - singlet - Artem
  566.         energy = 0.5 * E_MASS * g * g;               // electron energy
  567.         energy = fabs(energy + E_EXC_TH_2 * EV_TO_J);  // add energy for deexcitation
  568.         g   = sqrt(2.0 * energy / E_MASS);           // relative velocity after energy loss
  569.         chi = acos(1.0 - 2.0 * R01(MTgen));          // isotropic scattering
  570.         eta = TWO_PI * R01(MTgen);                   // azimuthal angle    
  571.  
  572.         //substract  excited He atom density from the grid point - Artem
  573.         //no need if we calculate rates and densities outside
  574.  //       e2_density[p] = std::max(e2_density[p] - WEIGHT / (ELECTRODE_AREA * DX), 0.0);
  575.     }
  576.  
  577.    
  578.     // scatter the primary electron
  579.    
  580.     sc = sin(chi);
  581.     cc = cos(chi);
  582.     se = sin(eta);
  583.     ce = cos(eta);
  584.    
  585.     // compute new relative velocity:
  586.    
  587.     gx = g * (ct * cc - st * sc * ce);
  588.     gy = g * (st * cp * cc + ct * cp * sc * ce - sp * sc * se);
  589.     gz = g * (st * sp * cc + ct * sp * sc * ce + cp * sc * se);
  590.    
  591.     // post-collision velocity of the colliding electron
  592.    
  593.     (*vxe) = wx + F2 * gx;
  594.     (*vye) = wy + F2 * gy;
  595.     (*vze) = wz + F2 * gz;
  596. }
  597.  
  598. //----------------------------------------------------------------------//
  599. // He+ / He collision                                                   //
  600. //----------------------------------------------------------------------//
  601.  
  602. void collision_ion (double *vx_1, double *vy_1, double *vz_1,
  603.                     double *vx_2, double *vy_2, double *vz_2, int e_index){
  604.     double   g,gx,gy,gz,wx,wy,wz,rnd;
  605.     double   theta,phi,chi,eta,st,ct,sp,cp,sc,cc,se,ce,t1,t2;
  606.    
  607.     // calculate relative velocity before collision
  608.     // random Maxwellian target atom already selected (vx_2,vy_2,vz_2 velocity components of target atom come with the call)
  609.    
  610.     gx = (*vx_1)-(*vx_2);
  611.     gy = (*vy_1)-(*vy_2);
  612.     gz = (*vz_1)-(*vz_2);
  613.     g  = sqrt(gx * gx + gy * gy + gz * gz);
  614.     wx = 0.5 * ((*vx_1) + (*vx_2));
  615.     wy = 0.5 * ((*vy_1) + (*vy_2));
  616.     wz = 0.5 * ((*vz_1) + (*vz_2));
  617.    
  618.     // find Euler angles
  619.    
  620.     if (gx == 0) {theta = 0.5 * PI;} else {theta = atan2(sqrt(gy * gy + gz * gz),gx);}
  621.     if (gy == 0) {
  622.         if (gz > 0){phi = 0.5 * PI;} else {phi = - 0.5 * PI;}
  623.     } else {phi = atan2(gz, gy);}
  624.    
  625.     // determine the type of collision based on cross sections and generate scattering angle
  626.    
  627.     t1  =      sigma[I_ISO][e_index];
  628.     t2  = t1 + sigma[I_BACK][e_index];
  629.     rnd = R01(MTgen);
  630.     if  (rnd < (t1 /t2)){                        // isotropic scattering
  631.         chi = acos(1.0 - 2.0 * R01(MTgen));      // scattering angle
  632.     } else {                                     // backward scattering
  633.         chi = PI;                                // scattering angle
  634.     }
  635.     eta = TWO_PI * R01(MTgen);                   // azimuthal angle
  636.     sc  = sin(chi);
  637.     cc  = cos(chi);
  638.     se  = sin(eta);
  639.     ce  = cos(eta);
  640.     st  = sin(theta);
  641.     ct  = cos(theta);
  642.     sp  = sin(phi);
  643.     cp  = cos(phi);
  644.    
  645.     // compute new relative velocity
  646.    
  647.     gx = g * (ct * cc - st * sc * ce);
  648.     gy = g * (st * cp * cc + ct * cp * sc * ce - sp * sc * se);
  649.     gz = g * (st * sp * cc + ct * sp * sc * ce + cp * sc * se);
  650.    
  651.     // post-collision velocity of the ion
  652.    
  653.     (*vx_1) = wx + 0.5 * gx;
  654.     (*vy_1) = wy + 0.5 * gy;
  655.     (*vz_1) = wz + 0.5 * gz;
  656. }
  657.  
  658. //-----------------------------------------------------------------//
  659. // solve Poisson equation (Thomas algorithm)                       //
  660. //-----------------------------------------------------------------//
  661.  
  662. void solve_Poisson (xvector rho1, double tt){
  663.     const double A =  1.0;
  664.     const double B = -2.0;
  665.     const double C =  1.0;
  666.     const double S = 1.0 / (2.0 * DX);
  667.     const double ALPHA = -DX * DX / EPSILON0;
  668.     xvector      g, w, f;
  669.     int          i;
  670.    
  671.     // apply potential to the electrodes - boundary conditions
  672.    
  673.     pot[0]     = VOLTAGE * cos(OMEGA * tt);         // potential at the powered electrode
  674.     pot[N_G-1] = 0.0;                               // potential at the grounded electrode
  675.    
  676.     // solve Poisson equation
  677.    
  678.     for(i=1; i<=N_G-2; i++) f[i] = ALPHA * rho1[i];
  679.     f[1] -= pot[0];
  680.     f[N_G-2] -= pot[N_G-1];
  681.     w[1] = C/B;
  682.     g[1] = f[1]/B;
  683.     for(i=2; i<=N_G-2; i++){
  684.         w[i] = C / (B - A * w[i-1]);
  685.         g[i] = (f[i] - A * g[i-1]) / (B - A * w[i-1]);
  686.     }
  687.     pot[N_G-2] = g[N_G-2];
  688.     for (i=N_G-3; i>0; i--) pot[i] = g[i] - w[i] * pot[i+1];            // potential at the grid points between the electrodes
  689.    
  690.     // compute electric field
  691.    
  692.     for(i=1; i<=N_G-2; i++) efield[i] = (pot[i-1] - pot[i+1]) * S;      // electric field at the grid points between the electrodes
  693.     efield[0]     = (pot[0]     - pot[1])     * INV_DX - rho1[0]     * DX / (2.0 * EPSILON0);   // powered electrode
  694.     efield[N_G-1] = (pot[N_G-2] - pot[N_G-1]) * INV_DX + rho1[N_G-1] * DX / (2.0 * EPSILON0);   // grounded electrode
  695. }
  696.  
  697. //---------------------------------------------------------------------//
  698. // simulation of one radiofrequency cycle                              //
  699. //---------------------------------------------------------------------//
  700.  
  701. void accumulate_rates() {
  702.     double v_sqr, velocity, energy, c0_temp;
  703.     int energy_index, p_temp;
  704.     const double Volume = (ELECTRODE_AREA * DX);
  705.  
  706.     for (int k=0; k<N_e; k++){                              
  707.         v_sqr = vx_e[k] * vx_e[k] + vy_e[k] * vy_e[k] + vz_e[k] * vz_e[k];
  708.         velocity = sqrt(v_sqr);
  709.         energy   = 0.5 * E_MASS * v_sqr / EV_TO_J;
  710.         energy_index = min( int(energy / DE_CS + 0.5), CS_RANGES-1);
  711.  
  712.         c0_temp = x_e[k] * INV_DX;
  713.         p_temp = std::max(0, std::min(N_G - 1, static_cast<int>(c0_temp)));
  714.    
  715.         sum_electron_density[p_temp] += WEIGHT / Volume;
  716.  
  717.         sum_rate1f[p_temp] += sigma[E_EXC_1][energy_index] * velocity * WEIGHT;
  718.         sum_rate2f[p_temp] += sigma[E_EXC_2][energy_index] * velocity * WEIGHT;
  719.  
  720.         sum_rate1b[p_temp] += sigma[E_SUPER_1][energy_index] * velocity * WEIGHT;
  721.         sum_rate2b[p_temp] += sigma[E_SUPER_2][energy_index] * velocity * WEIGHT;
  722.     }    
  723. }
  724.  
  725. // averaging the rates each RF cycle
  726. void average_rates() {
  727.     const double inv_NT = 1.0 / (N_avg * N_T); // averaging through N_avg RF periods each contains N_T cycles
  728.     const double inv_Volume = 1.0/(ELECTRODE_AREA * DX);
  729.     for (int p = 0; p < N_G; p++){
  730.         avg_electron_density[p] = sum_electron_density[p] * inv_NT;
  731.     }
  732.     for (int p = 0; p < N_G; p++) {
  733.         avg_rate1f[p] = sum_rate1f[p] * inv_NT * inv_Volume;  
  734.         avg_rate1b[p] = sum_rate1b[p] * inv_NT * inv_Volume;
  735.         avg_rate2f[p] = sum_rate2f[p] * inv_NT * inv_Volume;
  736.         avg_rate2b[p] = sum_rate2b[p] * inv_NT * inv_Volume;
  737.     }    
  738. }
  739.  
  740. void update_excited_dens() {
  741.  
  742.     xvector e1_density_bw;
  743.     xvector e2_density_bw;
  744.     xvector gas_dens_local;                                                   // local density of ground state atoms
  745.     double S0, S1, S2;                                                        // source terms for diffusion equation
  746.     double diff1, diff2;                                                      // diffusion terms
  747.     const double v_mean = sqrt(8.0*K_BOLTZMANN*T_neutral/(M_PI*HE_MASS));     // mean spead of He excited states, assuming T~Tg
  748.     bool converged = false;
  749.  
  750.     double accuracy = 1.0E-4;                                               // demanded accuracy
  751.     double alpha = 0.48;
  752.     double dt = alpha*DX*DX/Diff_coeff;
  753.     int max_iter = 1E8;                       // maximum iteration
  754.  
  755.     std::cout << Diff_coeff << " " <<  dt << " " << DX << "\n";
  756.  
  757.     // creating a helping array for backward step and also works with initial condition
  758.     std::memcpy(e1_density_bw, e1_density, sizeof(e1_density));      
  759.     std::memcpy(e2_density_bw, e2_density, sizeof(e2_density));
  760.  
  761.     for (int i = 0; i < N_G; i++){
  762.         gas_dens_local[i] = GAS_DENSITY;
  763.     }
  764.  
  765.    double rcmb_coeff = (-1.0)*gamma_k*v_mean/(2.0*(2.0-gamma_k)*Diff_coeff);
  766.  
  767.     for (int idx = 0; idx < max_iter; idx++) {
  768.  
  769.         // swapping the arrays
  770.         std::swap(e1_density_bw, e1_density);
  771.         std::swap(e2_density_bw, e2_density);            
  772.  
  773.         for (int i = 1; i < N_G-1; i++){
  774.             // calculate source terms of diffusion equation, S0 for neutral atoms of He
  775.             // S1 for triplet excited state, S2 for singlet excited state
  776.             // triplet and singlet are diffusing, neutral atoms are not
  777.  
  778.             S0 = dt*(-(avg_rate1f[i]+avg_rate2f[i])*gas_dens_local[i] + avg_rate1b[i]*e1_density_bw[i] + avg_rate2b[i]*e2_density_bw[i]);
  779.             S1 = dt*(avg_rate1f[i]*gas_dens_local[i] - avg_rate1b[i]*e1_density_bw[i]);
  780.             S2 = dt*(avg_rate2f[i]*gas_dens_local[i] - avg_rate2b[i]*e2_density_bw[i]);
  781.  
  782.             diff1 = e1_density_bw[i]*(1.0 - 2.0*alpha) + alpha*(e1_density_bw[i-1] + e1_density_bw[i+1]);
  783.             diff2 = e2_density_bw[i]*(1.0 - 2.0*alpha) + alpha*(e2_density_bw[i-1] + e2_density_bw[i+1]);
  784.  
  785.  
  786.             e1_density[i]      = e1_density_bw[i] + S1;
  787.             e2_density[i]      = e2_density_bw[i] + S2;
  788. //            gas_dens_local[i] += S0;
  789.  
  790.             // Prevent negative densities
  791. //            gas_dens_local[i] = std::max(gas_dens_local[i], 0.0);  
  792.             e1_density[i]     = std::max(e1_density[i], 0.0);
  793.             e2_density[i]     = std::max(e2_density[i], 0.0);
  794.         }
  795.  
  796.         // boundary conditions: now it's zero so no excited states density at the electrodes, yield is zero
  797.         e1_density[0] = e1_density[1]/(rcmb_coeff*DX + 1.0);
  798.         e1_density[N_G-1] = e1_density[N_G-2]/(rcmb_coeff*DX + 1.0);
  799.         e2_density[0] = e2_density[1]/(rcmb_coeff*DX + 1.0);
  800.         e2_density[N_G-1] = e2_density[N_G-2]/(rcmb_coeff*DX + 1.0);        
  801.  
  802.         //checking convergence        
  803.         double rel1 = 0.0, rel2 = 0.0;
  804.         for (int i = 1; i < N_G-1; ++i) {
  805.             double abs1 = fabs(e1_density[i] - e1_density_bw[i]);
  806.             double abs2 = fabs(e2_density[i] - e2_density_bw[i]);
  807.             double base1 = std::max(e1_density[i], 1e-12);
  808.             double base2 = std::max(e2_density[i], 1e-12);
  809.             rel1 = std::max(rel1, abs1 / e1_density_bw[i]);
  810.             rel2 = std::max(rel2, abs2 / e2_density_bw[i]);
  811.         }
  812.  
  813.         if (rel1 < accuracy && rel2 < accuracy) {
  814.             converged = true;
  815.             std::cout << "Steady-state reached after " << idx << " iterations.\n";
  816.             std::cout << "Relative changes are: " << rel1 << " " << rel2 << "\n";
  817.             break;
  818.         }
  819.     }
  820.  
  821.     if (!converged) {
  822.         std::cerr << "Steady-state not reached after " << max_iter << " iterations.\n";
  823.     }    
  824. }
  825.  
  826.  
  827. void do_one_cycle (void){
  828.     const double DV       = ELECTRODE_AREA * DX;
  829.     const double FACTOR_W = WEIGHT / DV;
  830.     const double FACTOR_E = DT_E / E_MASS * E_CHARGE;
  831.     const double FACTOR_I = DT_I / HE_MASS * E_CHARGE;
  832.     const double MIN_X    = 0.45 * L;                       // min. position for EEPF collection
  833.     const double MAX_X    = 0.55 * L;                       // max. position for EEPF collection
  834.     int      k, t, p, energy_index;
  835.     double   g, g_sqr, gx, gy, gz, vx_a, vy_a, vz_a, e_x, energy, nu, p_coll, v_sqr, velocity;
  836.     double   mean_v, c0, c1, c2, rate;
  837.     bool     out;
  838.     xvector  rho;
  839.     int      t_index;
  840.  
  841.     nu_avg = 0.0;
  842.    
  843.     for (t=0; t<N_T; t++){          // the RF period is divided into N_T equal time intervals (time step DT_E)
  844.         Time += DT_E;               // update of the total simulated time
  845.         t_index = t / N_BIN;        // index for XT distributions
  846.        
  847.         // step 1: compute densities at grid points
  848.        
  849.         for(p=0; p<N_G; p++) e_density[p] = 0;                             // electron density - computed in every time step
  850.         for(k=0; k<N_e; k++){
  851.  
  852.             if      (p < 0)        p = 0;
  853.             else if (p > N_G - 2)  p = N_G - 2;
  854.             c0 = x_e[k] * INV_DX;
  855.             p  = int(c0);
  856.             e_density[p]   += (p + 1 - c0) * FACTOR_W;
  857.             e_density[p+1] += (c0 - p) * FACTOR_W;
  858.         }
  859.         e_density[0]     *= 2.0; // double at the edge bcs working with half-domain (no left/right neighbour)
  860.         e_density[N_G-1] *= 2.0;
  861.         for(p=0; p<N_G; p++) cumul_e_density[p] += e_density[p];
  862.        
  863.         if ((t % N_SUB) == 0) {                                            // ion density - computed in every N_SUB-th time steps (subcycling)
  864.             for(p=0; p<N_G; p++) i_density[p] = 0;
  865.             for(k=0; k<N_i; k++){
  866.                 c0 = x_i[k] * INV_DX;
  867.                 p  = int(c0);
  868.                 i_density[p]   += (p + 1 - c0) * FACTOR_W;  
  869.                 i_density[p+1] += (c0 - p) * FACTOR_W;
  870.             }
  871.             i_density[0]     *= 2.0; // double at the edge bcs working with half-domain (no left/right neighbour)
  872.             i_density[N_G-1] *= 2.0;
  873.         }
  874.         for(p=0; p<N_G; p++) cumul_i_density[p] += i_density[p];
  875.        
  876.         // step 2: solve Poisson equation
  877.        
  878.         for(p=0; p<N_G; p++) rho[p] = E_CHARGE * (i_density[p] - e_density[p]);  // get charge density
  879.         solve_Poisson(rho,Time);                                                 // compute potential and electric field
  880.        
  881.         // steps 3 & 4: move particles according to electric field interpolated to particle positions
  882.        
  883.         for(k=0; k<N_e; k++){                       // move all electrons in every time step
  884.             c0  = x_e[k] * INV_DX;
  885.             p   = int(c0);
  886.             c1  = p + 1.0 - c0;
  887.             c2  = c0 - p;
  888.             e_x = c1 * efield[p] + c2 * efield[p+1];
  889.            
  890.             if (measurement_mode) {
  891.                
  892.                 // measurements: 'x' and 'v' are needed at the same time, i.e. old 'x' and mean 'v'
  893.                
  894.                 mean_v = vx_e[k] - 0.5 * e_x * FACTOR_E;
  895.                 counter_e_xt[p][t_index]   += c1;
  896.                 counter_e_xt[p+1][t_index] += c2;
  897.                 ue_xt[p][t_index]   += c1 * mean_v;
  898.                 ue_xt[p+1][t_index] += c2 * mean_v;
  899.                 v_sqr  = mean_v * mean_v + vy_e[k] * vy_e[k] + vz_e[k] * vz_e[k];
  900.                 energy = 0.5 * E_MASS * v_sqr / EV_TO_J;
  901.                 meanee_xt[p][t_index]   += c1 * energy;
  902.                 meanee_xt[p+1][t_index] += c2 * energy;
  903.                 energy_index = min( int(energy / DE_CS + 0.5), CS_RANGES-1);
  904.                 velocity = sqrt(v_sqr);
  905.                 double local_neut_dens = GAS_DENSITY - e1_density[p] - e2_density[p];
  906.                 rate = sigma[E_ION][energy_index] * velocity * DT_E * local_neut_dens;
  907.                 ioniz_rate_xt[p][t_index]   += c1 * rate;
  908.                 ioniz_rate_xt[p+1][t_index] += c2 * rate;
  909.  
  910.                 // measure EEPF in the center
  911.                
  912.                 if ((MIN_X < x_e[k]) && (x_e[k] < MAX_X)){
  913.                     energy_index = (int)(energy / DE_EEPF);
  914.                     if (energy_index < N_EEPF) {eepf[energy_index] += 1.0;}
  915.                     mean_energy_accu_center += energy;
  916.                     mean_energy_counter_center++;
  917.                 }
  918.             }
  919.            
  920.             // update velocity and position
  921.            
  922.             vx_e[k] -= e_x * FACTOR_E;
  923.             x_e[k]  += vx_e[k] * DT_E;
  924.         }
  925.        
  926.         if ((t % N_SUB) == 0) {                       // move all ions in every N_SUB-th time steps (subcycling)
  927.             for(k=0; k<N_i; k++){
  928.                 c0  = x_i[k] * INV_DX;
  929.                 p   = int(c0);
  930.                 c1  = p + 1 - c0;
  931.                 c2  = c0 - p;
  932.                 e_x = c1 * efield[p] + c2 * efield[p+1];
  933.                
  934.                 if (measurement_mode) {
  935.                    
  936.                     // measurements: 'x' and 'v' are needed at the same time, i.e. old 'x' and mean 'v'
  937.  
  938.                     mean_v = vx_i[k] + 0.5 * e_x * FACTOR_I;
  939.                     counter_i_xt[p][t_index]   += c1;
  940.                     counter_i_xt[p+1][t_index] += c2;
  941.                     ui_xt[p][t_index]   += c1 * mean_v;
  942.                     ui_xt[p+1][t_index] += c2 * mean_v;
  943.                     v_sqr  = mean_v * mean_v + vy_i[k] * vy_i[k] + vz_i[k] * vz_i[k];
  944.                     energy = 0.5 * HE_MASS * v_sqr / EV_TO_J;
  945.                     meanei_xt[p][t_index]   += c1 * energy;
  946.                     meanei_xt[p+1][t_index] += c2 * energy;
  947.                 }
  948.                
  949.                 // update velocity and position and accumulate absorbed energy
  950.                
  951.                 vx_i[k] += e_x * FACTOR_I;
  952.                 x_i[k]  += vx_i[k] * DT_I;
  953.             }
  954.         }
  955.        
  956.         // step 5: check boundaries -- changed by Artem
  957.        
  958.         k = 0;
  959.         while(k < N_e) {    // check boundaries for all electrons in every time step
  960.             out = false;
  961.             if ((x_e[k] < 0) || (x_e[k] > L)) {out = true;}                   // the electron is out at the electrodes
  962.             if (out) {
  963.                 if (R01(MTgen)< r) {                                          // reflecting elastically with r probability
  964.                     x_e[k] < 0 ? x_e[k] *= -1.0 : x_e[k] = 2.0*L - x_e[k];    // if left/right border -> put on a left/right border
  965.                     vx_e[k] *= -1.0;                                          // elastic reflection                          
  966.                     }
  967.                 else {                                                        // remove the electron
  968.                     x_e[k] < 0 ? N_e_abs_pow++ : N_e_abs_gnd++;               // absorption calculation at the powered/grounded (left/right) electrode
  969.                     x_e [k] = x_e [N_e-1];                                    // pushing last element on a vacant place
  970.                     vx_e[k] = vx_e[N_e-1];
  971.                     vy_e[k] = vy_e[N_e-1];
  972.                     vz_e[k] = vz_e[N_e-1];
  973.                     N_e--;
  974.                 }
  975.             } else k++;
  976.         }
  977.        
  978.         if ((t % N_SUB) == 0) {   // check boundaries for all ions in every N_SUB-th time steps (subcycling)
  979.             k = 0;
  980.             while(k < N_i) {
  981.                 out = false;
  982.                 if (x_i[k] < 0) {       // the ion is out at the powered electrode
  983.                     N_i_abs_pow++;
  984.                     out    = true;
  985.                     v_sqr  = vx_i[k] * vx_i[k] + vy_i[k] * vy_i[k] + vz_i[k] * vz_i[k];
  986.                     energy = 0.5 * HE_MASS *  v_sqr/ EV_TO_J;
  987.                     energy_index = (int)(energy / DE_IFED);
  988.                     if (energy_index < N_IFED) {ifed_pow[energy_index]++;}       // save IFED at the powered electrode
  989.  
  990.                     if (R01(MTgen)< gamma_i) {
  991.                         if (N_e < MAX_N_P){                                                     // adding a new electron on the left electrode
  992.                             N_e++;                                                              // with energy sampled from Maxwellian distribution
  993.                             vx_e[N_e-1] = RMB_e(MTgen); vy_e[N_e-1] = RMB_e(MTgen); vz_e[N_e-1] = RMB_e(MTgen);
  994.                             x_e[N_e-1] = 0.0;
  995.                         }
  996.                         else{
  997.                             std::cerr << "Impossible to emit a new SE at the powered electrode" <<"\n";
  998.                         }
  999.                     }
  1000.                 }
  1001.                 if (x_i[k] > L) {       // the ion is out at the grounded electrode
  1002.                     N_i_abs_gnd++;
  1003.                     out    = true;
  1004.                     v_sqr  = vx_i[k] * vx_i[k] + vy_i[k] * vy_i[k] + vz_i[k] * vz_i[k];
  1005.                     energy = 0.5 * HE_MASS * v_sqr / EV_TO_J;
  1006.                     energy_index = (int)(energy / DE_IFED);
  1007.                     if (energy_index < N_IFED) {ifed_gnd[energy_index]++;}        // save IFED at the grounded electrode
  1008.  
  1009.                     if (R01(MTgen)< gamma_i) {
  1010.                         if (N_e < MAX_N_P){                                                     // adding a new electron on the left electrode
  1011.                             N_e++;                                                              // with energy sampled from Maxwellian distribution
  1012.                             vx_e[N_e-1] = RMB_e(MTgen); vy_e[N_e-1] = RMB_e(MTgen); vz_e[N_e-1] = RMB_e(MTgen);
  1013.                             x_e[N_e-1] = L;
  1014.                         }
  1015.                         else{
  1016.                             std::cerr << "Impossible to emit a new SE at the grounded electrode" <<"\n";
  1017.                         }
  1018.                     }                  
  1019.                 }
  1020.  
  1021.                 if (out) {  // delete the ion, if out
  1022.                     x_i [k] = x_i [N_i-1];
  1023.                     vx_i[k] = vx_i[N_i-1];
  1024.                     vy_i[k] = vy_i[N_i-1];
  1025.                     vz_i[k] = vz_i[N_i-1];
  1026.                     N_i--;
  1027.                 } else k++;
  1028.             }
  1029.         }
  1030.        
  1031.         // step 6: collisions
  1032.  
  1033.        
  1034.        
  1035.         for (k=0; k<N_e; k++){                              // checking for occurrence of a collision for all electrons in every time step
  1036.             v_sqr = vx_e[k] * vx_e[k] + vy_e[k] * vy_e[k] + vz_e[k] * vz_e[k];
  1037.             velocity = sqrt(v_sqr);
  1038.             energy   = 0.5 * E_MASS * v_sqr / EV_TO_J;
  1039.             energy_index = min( int(energy / DE_CS + 0.5), CS_RANGES-1);
  1040.  
  1041.             // Artem  - adding superelastic impact on total collisoinal probability//
  1042.  
  1043.            
  1044.             int e_crdnt = std::max(0, std::min(N_G - 1, static_cast<int>(x_e[k] * INV_DX)));
  1045.             double sigma_super_e = sigma[E_SUPER_1][energy_index] * e1_density[e_crdnt] + sigma[E_SUPER_2][energy_index] * e2_density[e_crdnt];
  1046.             double ground_dens_local = GAS_DENSITY - e1_density[e_crdnt] - e2_density[e_crdnt];
  1047.             double sigma_ground = (sigma[E_ELA][energy_index] + sigma[E_EXC_1][energy_index] +
  1048.                                 sigma[E_EXC_2][energy_index] + sigma[E_ION][energy_index]) * ground_dens_local;
  1049.             nu = (sigma_ground + sigma_super_e) * velocity;
  1050.  
  1051.             nu_avg += nu;
  1052.            
  1053.             p_coll = 1 - exp(- nu * DT_E);                  // collision probability for electrons
  1054.             if (R01(MTgen) < p_coll) {                      // electron collision takes place
  1055.                 collision_electron(x_e[k], &vx_e[k], &vy_e[k], &vz_e[k], energy_index);
  1056.                 N_e_coll++;
  1057.             }
  1058.         }
  1059.        
  1060.         if ((t % N_SUB) == 0) {                             // checking for occurrence of a collision for all ions in every N_SUB-th time steps (subcycling)
  1061.             for (k=0; k<N_i; k++){
  1062.                 vx_a = RMB_n(MTgen);                          // pick velocity components of a random target gas atom
  1063.                 vy_a = RMB_n(MTgen);
  1064.                 vz_a = RMB_n(MTgen);
  1065.                 gx   = vx_i[k] - vx_a;                       // compute the relative velocity of the collision partners
  1066.                 gy   = vy_i[k] - vy_a;
  1067.                 gz   = vz_i[k] - vz_a;
  1068.                 g_sqr = gx * gx + gy * gy + gz * gz;
  1069.                 g = sqrt(g_sqr);
  1070.                 energy = 0.5 * MU_HEHE * g_sqr / EV_TO_J;
  1071.                 energy_index = min( int(energy / DE_CS + 0.5), CS_RANGES-1);
  1072.                 nu = sigma_tot_i[energy_index] * g;
  1073.                 p_coll = 1 - exp(- nu * DT_I);              // collision probability for ions
  1074.                 if (R01(MTgen)< p_coll) {                   // ion collision takes place
  1075.                     collision_ion (&vx_i[k], &vy_i[k], &vz_i[k], &vx_a, &vy_a, &vz_a, energy_index);
  1076.                     N_i_coll++;
  1077.                 }
  1078.             }
  1079.         }
  1080.  
  1081.         //step 7: accumulate rates
  1082.         accumulate_rates();
  1083.  
  1084.         if (measurement_mode) {
  1085.            
  1086.             // collect 'xt' data from the grid
  1087.            
  1088.             for (p=0; p<N_G; p++) {
  1089.                 pot_xt   [p][t_index] += pot[p];
  1090.                 efield_xt[p][t_index] += efield[p];
  1091.                 ne_xt    [p][t_index] += e_density[p];
  1092.                 ni_xt    [p][t_index] += i_density[p];
  1093.                 e1_xt    [p][t_index] += e1_density[p];  // Artem
  1094.                 e2_xt    [p][t_index] += e2_density[p];  // Artem
  1095.             }
  1096.         }
  1097.        
  1098.         if ((t % 1000) == 0) printf(" c = %8d  t = %8d  #e = %8d  #i = %8d\n", cycle,t,N_e,N_i);
  1099.     }
  1100.  
  1101.     counter++;
  1102.  
  1103.     // updating denisites each N_avg cycles: --- Artem
  1104.     if (counter%N_avg == 0) {
  1105.         // compute average rates over a cycle
  1106.         average_rates();
  1107.         // updating densities
  1108.         update_excited_dens();
  1109.         // reset accumulators
  1110.         memset(sum_rate1f, 0, sizeof(sum_rate1f));
  1111.         memset(sum_rate1b, 0, sizeof(sum_rate1b));
  1112.         memset(sum_rate2f, 0, sizeof(sum_rate2f));
  1113.         memset(sum_rate2b, 0, sizeof(sum_rate2b));
  1114.         memset(sum_electron_density, 0, sizeof(sum_electron_density));  
  1115.     }    
  1116.  
  1117.  
  1118.     //calculate nu electron average:
  1119.  
  1120.     nu_avg /= (N_T*N_e);
  1121.  
  1122.     fprintf(datafile,"%8d  %8d  %8d\n",cycle,N_e,N_i);
  1123.     print_excitation_densities();
  1124. }
  1125.  
  1126. //---------------------------------------------------------------------//
  1127. // save particle coordinates                                           //
  1128. //---------------------------------------------------------------------//
  1129.  
  1130. void save_particle_data(){
  1131.     double   d;
  1132.     FILE   * f;
  1133.     char fname[80];
  1134.    
  1135.     strcpy(fname,"picdata.bin");
  1136.     f = fopen(fname,"wb");
  1137.     fwrite(&Time,sizeof(double),1,f);
  1138.     d = (double)(cycles_done);
  1139.     fwrite(&d,sizeof(double),1,f);
  1140.     d = (double)(N_e);
  1141.     fwrite(&d,sizeof(double),1,f);
  1142.     fwrite(x_e, sizeof(double),N_e,f);
  1143.     fwrite(vx_e,sizeof(double),N_e,f);
  1144.     fwrite(vy_e,sizeof(double),N_e,f);
  1145.     fwrite(vz_e,sizeof(double),N_e,f);
  1146.     d = (double)(N_i);
  1147.     fwrite(&d,sizeof(double),1,f);
  1148.     fwrite(x_i, sizeof(double),N_i,f);
  1149.     fwrite(vx_i,sizeof(double),N_i,f);
  1150.     fwrite(vy_i,sizeof(double),N_i,f);
  1151.     fwrite(vz_i,sizeof(double),N_i,f);
  1152.  
  1153.     // saving excited state densities - Artem
  1154.  
  1155.     fwrite(e1_density, sizeof(double), N_G, f);
  1156.     fwrite(e2_density, sizeof(double), N_G, f);    
  1157.  
  1158.     fclose(f);
  1159.     printf(">> eduPIC: data saved : %d electrons %d ions, excited states densities , %d cycles completed, time is %e [s]\n",N_e,N_i,cycles_done,Time);
  1160. }
  1161.  
  1162. //---------------------------------------------------------------------//
  1163. // load particle coordinates                                           //
  1164. //---------------------------------------------------------------------//
  1165.  
  1166. void load_particle_data(){
  1167.     double   d;
  1168.     FILE   * f;
  1169.     char fname[80];
  1170.    
  1171.     strcpy(fname,"picdata.bin");    
  1172.     f = fopen(fname,"rb");
  1173.     if (f==NULL) {printf(">> eduPIC: ERROR: No particle data file found, try running initial cycle using argument '0'\n"); exit(0); }
  1174.     fread(&Time,sizeof(double),1,f);
  1175.     fread(&d,sizeof(double),1,f);
  1176.     cycles_done = int(d);
  1177.     fread(&d,sizeof(double),1,f);
  1178.     N_e = int(d);
  1179.     fread(x_e, sizeof(double),N_e,f);
  1180.     fread(vx_e,sizeof(double),N_e,f);
  1181.     fread(vy_e,sizeof(double),N_e,f);
  1182.     fread(vz_e,sizeof(double),N_e,f);
  1183.     fread(&d,sizeof(double),1,f);
  1184.     N_i = int(d);
  1185.     fread(x_i, sizeof(double),N_i,f);
  1186.     fread(vx_i,sizeof(double),N_i,f);
  1187.     fread(vy_i,sizeof(double),N_i,f);
  1188.     fread(vz_i,sizeof(double),N_i,f);
  1189.  
  1190.     // reading excited states densities -- Artem
  1191.  
  1192.     fread(e1_density, sizeof(double), N_G, f);
  1193.     fread(e2_density, sizeof(double), N_G, f);    
  1194.  
  1195.     fclose(f);
  1196.     printf(">> eduPIC: data loaded : %d electrons %d ions, excited states densities, %d cycles completed before, time is %e [s]\n",N_e,N_i,cycles_done,Time);
  1197. }
  1198.  
  1199. //---------------------------------------------------------------------//
  1200. // save density data                                                   //
  1201. //---------------------------------------------------------------------//
  1202.  
  1203. void save_density(void){
  1204.     FILE *f;
  1205.     double c;
  1206.     int m;
  1207.    
  1208.     f = fopen("density.dat","w");
  1209.     c = 1.0 / (double)(no_of_cycles) / (double)(N_T);
  1210.     for(m=0; m<N_G; m++){
  1211.         fprintf(f,"%8.5f  %12e  %12e\n",m * DX, cumul_e_density[m] * c, cumul_i_density[m] * c);
  1212.     }
  1213.     fclose(f);
  1214. }
  1215.  
  1216. // save Final excited states densities - Artem
  1217.  
  1218. void save_final_excited_densities(void) {
  1219.     FILE *f = fopen("excited_densities.dat", "w");
  1220.     for(int p=0; p<N_G; p++) {
  1221.         fprintf(f, "%8.5f %12e %12e\n", p*DX, e1_density[p], e2_density[p]);
  1222.     }
  1223.     fclose(f);
  1224. }
  1225.  
  1226. //---------------------------------------------------------------------//
  1227. // save EEPF data                                                      //
  1228. //---------------------------------------------------------------------//
  1229.  
  1230. void save_eepf(void) {
  1231.     FILE   *f;
  1232.     int    i;
  1233.     double h,energy;
  1234.    
  1235.     h = 0.0;
  1236.     for (i=0; i<N_EEPF; i++) {h += eepf[i];}
  1237.     h *= DE_EEPF;
  1238.     f = fopen("eepf.dat","w");
  1239.     for (i=0; i<N_EEPF; i++) {
  1240.         energy = (i + 0.5) * DE_EEPF;
  1241.         fprintf(f,"%e  %e\n", energy, eepf[i] / h / sqrt(energy));
  1242.     }
  1243.     fclose(f);
  1244. }
  1245.  
  1246. //---------------------------------------------------------------------//
  1247. // save IFED data                                                      //
  1248. //---------------------------------------------------------------------//
  1249.  
  1250. void save_ifed(void) {
  1251.     FILE   *f;
  1252.     int    i;
  1253.     double h_pow,h_gnd,energy;
  1254.    
  1255.     h_pow = 0.0;
  1256.     h_gnd = 0.0;
  1257.     for (i=0; i<N_IFED; i++) {h_pow += ifed_pow[i]; h_gnd += ifed_gnd[i];}
  1258.     h_pow *= DE_IFED;
  1259.     h_gnd *= DE_IFED;
  1260.     mean_i_energy_pow = 0.0;
  1261.     mean_i_energy_gnd = 0.0;
  1262.     f = fopen("ifed.dat","w");
  1263.     for (i=0; i<N_IFED; i++) {
  1264.         energy = (i + 0.5) * DE_IFED;
  1265.         fprintf(f,"%6.2f %10.6f %10.6f\n", energy, (double)(ifed_pow[i])/h_pow, (double)(ifed_gnd[i])/h_gnd);
  1266.         mean_i_energy_pow += energy * (double)(ifed_pow[i]) / h_pow;
  1267.         mean_i_energy_gnd += energy * (double)(ifed_gnd[i]) / h_gnd;
  1268.     }
  1269.     fclose(f);
  1270. }
  1271.  
  1272. //--------------------------------------------------------------------//
  1273. // save XT data                                                       //
  1274. //--------------------------------------------------------------------//
  1275.  
  1276. void save_xt_1(xt_distr distr, char *fname) {
  1277.     FILE   *f;
  1278.     int    i, j;
  1279.    
  1280.     f = fopen(fname,"w");
  1281.     for (i=0; i<N_G; i++){
  1282.         for (j=0; j<N_XT; j++){
  1283.             fprintf(f,"%e  ", distr[i][j]);
  1284.         }
  1285.         fprintf(f,"\n");
  1286.     }
  1287.     fclose(f);
  1288. }
  1289.  
  1290. void norm_all_xt(void){
  1291.     double f1, f2;
  1292.     int    i, j;
  1293.    
  1294.     // normalize all XT data
  1295.    
  1296.     f1 = (double)(N_XT) / (double)(no_of_cycles * N_T);
  1297.     f2 = WEIGHT / (ELECTRODE_AREA * DX) / (no_of_cycles * (PERIOD / (double)(N_XT)));
  1298.    
  1299.     for (i=0; i<N_G; i++){
  1300.         for (j=0; j<N_XT; j++){
  1301.             pot_xt[i][j]    *= f1;
  1302.             efield_xt[i][j] *= f1;
  1303.             ne_xt[i][j]     *= f1;
  1304.             ni_xt[i][j]     *= f1;
  1305.             e1_xt[i][j]     *= f1;   // Artem
  1306.             e2_xt[i][j]     *= f1;   // Artem
  1307.             if (counter_e_xt[i][j] > 0) {
  1308.                 ue_xt[i][j]     =  ue_xt[i][j] / counter_e_xt[i][j];
  1309.                 je_xt[i][j]     = -ue_xt[i][j] * ne_xt[i][j] * E_CHARGE;
  1310.                 meanee_xt[i][j] =  meanee_xt[i][j] / counter_e_xt[i][j];
  1311.                 ioniz_rate_xt[i][j] *= f2;
  1312.              } else {
  1313.                 ue_xt[i][j]         = 0.0;
  1314.                 je_xt[i][j]         = 0.0;
  1315.                 meanee_xt[i][j]     = 0.0;
  1316.                 ioniz_rate_xt[i][j] = 0.0;
  1317.             }
  1318.             if (counter_i_xt[i][j] > 0) {
  1319.                 ui_xt[i][j]     = ui_xt[i][j] / counter_i_xt[i][j];
  1320.                 ji_xt[i][j]     = ui_xt[i][j] * ni_xt[i][j] * E_CHARGE;
  1321.                 meanei_xt[i][j] = meanei_xt[i][j] / counter_i_xt[i][j];
  1322.             } else {
  1323.                 ui_xt[i][j]     = 0.0;
  1324.                 ji_xt[i][j]     = 0.0;
  1325.                 meanei_xt[i][j] = 0.0;
  1326.             }
  1327.             powere_xt[i][j] = je_xt[i][j] * efield_xt[i][j];
  1328.             poweri_xt[i][j] = ji_xt[i][j] * efield_xt[i][j];
  1329.         }
  1330.     }
  1331. }
  1332.  
  1333. void save_all_xt(void){
  1334.     char fname[80];
  1335.    
  1336.     strcpy(fname,"pot_xt.dat");     save_xt_1(pot_xt, fname);
  1337.     strcpy(fname,"efield_xt.dat");  save_xt_1(efield_xt, fname);
  1338.     strcpy(fname,"ne_xt.dat");      save_xt_1(ne_xt, fname);
  1339.     strcpy(fname,"ni_xt.dat");      save_xt_1(ni_xt, fname);
  1340.     strcpy(fname,"je_xt.dat");      save_xt_1(je_xt, fname);
  1341.     strcpy(fname,"ji_xt.dat");      save_xt_1(ji_xt, fname);
  1342.     strcpy(fname,"powere_xt.dat");  save_xt_1(powere_xt, fname);
  1343.     strcpy(fname,"poweri_xt.dat");  save_xt_1(poweri_xt, fname);
  1344.     strcpy(fname,"meanee_xt.dat");  save_xt_1(meanee_xt, fname);
  1345.     strcpy(fname,"meanei_xt.dat");  save_xt_1(meanei_xt, fname);
  1346.     strcpy(fname,"ioniz_xt.dat");   save_xt_1(ioniz_rate_xt, fname);
  1347.     strcpy(fname,"e1_xt.dat");      save_xt_1(e1_xt, fname);
  1348.     strcpy(fname,"e2_xt.dat");      save_xt_1(e2_xt, fname);
  1349. }
  1350.  
  1351. //---------------------------------------------------------------------//
  1352. // simulation report including stability and accuracy conditions       //
  1353. //---------------------------------------------------------------------//
  1354.  
  1355. void check_and_save_info(void){
  1356.     FILE     *f;
  1357.     double   plas_freq, meane, kT, debye_length, density, ecoll_freq, icoll_freq, sim_time, e_max, v_max, power_e, power_i, c;
  1358.     int      i,j;
  1359.     bool     conditions_OK;
  1360.    
  1361.     density    = cumul_e_density[N_G / 2] / (double)(no_of_cycles) / (double)(N_T);  // e density @ center
  1362.     plas_freq  = E_CHARGE * sqrt(density / EPSILON0 / E_MASS);                       // e plasma frequency @ center
  1363.     meane      = mean_energy_accu_center / (double)(mean_energy_counter_center);     // e mean energy @ center
  1364.     kT         = 2.0 * meane * EV_TO_J / 3.0;                                        // k T_e @ center (approximate)
  1365.     sim_time   = (double)(no_of_cycles) / FREQUENCY;                                 // simulated time
  1366.     ecoll_freq = (double)(N_e_coll) / sim_time / (double)(N_e);                      // e collision frequency
  1367.     icoll_freq = (double)(N_i_coll) / sim_time / (double)(N_i);                      // ion collision frequency
  1368.     debye_length = sqrt(EPSILON0 * kT / density) / E_CHARGE;                         // e Debye length @ center
  1369.    
  1370.     f = fopen("info.txt","w");
  1371.     fprintf(f,"########################## eduPIC simulation report ############################\n");
  1372.     fprintf(f,"Simulation parameters:\n");
  1373.     fprintf(f,"Gap distance                          = %12.3e [m]\n",  L);
  1374.     fprintf(f,"# of grid divisions                   = %12d\n",      N_G);
  1375.     fprintf(f,"Frequency                             = %12.3e [Hz]\n", FREQUENCY);
  1376.     fprintf(f,"# of time steps / period              = %12d\n",      N_T);
  1377.     fprintf(f,"# of electron / ion time steps        = %12d\n",      N_SUB);
  1378.     fprintf(f,"Voltage amplitude                     = %12.3e [V]\n",  VOLTAGE);
  1379.     fprintf(f,"Pressure (Ar)                         = %12.3e [Pa]\n", PRESSURE);
  1380.     fprintf(f,"Temperature                           = %12.3e [K]\n",  T_neutral);
  1381.     fprintf(f,"Superparticle weight                  = %12.3e\n",      WEIGHT);
  1382.     fprintf(f,"# of simulation cycles in this run    = %12d\n",      no_of_cycles);
  1383.     fprintf(f,"--------------------------------------------------------------------------------\n");
  1384.     fprintf(f,"Plasma characteristics:\n");
  1385.     fprintf(f,"Electron density @ center             = %12.3e [m^{-3}]\n", density);
  1386.     fprintf(f,"Plasma frequency @ center             = %12.3e [rad/s]\n",  plas_freq);
  1387.     fprintf(f,"Debye length @ center                 = %12.3e [m]\n",      debye_length);
  1388.     fprintf(f,"Electron collision frequency          = %12.3e [1/s]\n",    ecoll_freq);
  1389.     fprintf(f,"Ion collision frequency               = %12.3e [1/s]\n",    icoll_freq);
  1390.     fprintf(f,"--------------------------------------------------------------------------------\n");
  1391.     fprintf(f,"Stability and accuracy conditions:\n");
  1392.     conditions_OK = true;
  1393.     c = plas_freq * DT_E;
  1394.     fprintf(f,"Plasma frequency @ center * DT_E      = %12.3f (OK if less than 0.20)\n", c);
  1395.     if (c > 0.2) {conditions_OK = false;}
  1396.     c = DX / debye_length;
  1397.     fprintf(f,"DX / Debye length @ center            = %12.3f (OK if less than 1.00)\n", c);
  1398.     if (c > 1.0) {conditions_OK = false;}
  1399.     c = max_electron_coll_freq() * DT_E;
  1400.     fprintf(f,"Max. electron coll. frequency * DT_E  = %12.3f (OK if less than 0.05)\n", c);
  1401.     if (c > 0.05) {conditions_OK = false;}
  1402.     c = max_ion_coll_freq() * DT_I;
  1403.     fprintf(f,"Max. ion coll. frequency * DT_I       = %12.3f (OK if less than 0.05)\n", c);
  1404.     if (c > 0.05) {conditions_OK = false;}
  1405.     if (conditions_OK == false){
  1406.         fprintf(f,"--------------------------------------------------------------------------------\n");
  1407.         fprintf(f,"** STABILITY AND ACCURACY CONDITION(S) VIOLATED - REFINE SIMULATION SETTINGS! **\n");
  1408.         fprintf(f,"--------------------------------------------------------------------------------\n");
  1409.         fclose(f);
  1410.         printf(">> eduPIC: ERROR: STABILITY AND ACCURACY CONDITION(S) VIOLATED!\n");
  1411.         printf(">> eduPIC: for details see 'info.txt' and refine simulation settings!\n");
  1412.     }
  1413.     else
  1414.     {
  1415.         // calculate maximum energy for which the Courant-Friedrichs-Levy condition holds:
  1416.        
  1417.         v_max = DX / DT_E;
  1418.         e_max = 0.5 * E_MASS * v_max * v_max / EV_TO_J;
  1419.         fprintf(f,"Max e- energy for CFL condition       = %12.3f [eV]\n", e_max);
  1420.         fprintf(f,"Check EEPF to ensure that CFL is fulfilled for the majority of the electrons!\n");
  1421.         fprintf(f,"--------------------------------------------------------------------------------\n");
  1422.        
  1423.         // saving of the following data is done here as some of the further lines need data
  1424.         // that are computed / normalized in these functions
  1425.        
  1426.         printf(">> eduPIC: saving diagnostics data\n");
  1427.         save_density();
  1428.         save_final_excited_densities();   // Artem
  1429.         save_eepf();
  1430.         save_ifed();
  1431.         norm_all_xt();
  1432.         save_all_xt();
  1433.         fprintf(f,"Particle characteristics at the electrodes:\n");
  1434.         fprintf(f,"Ion flux at powered electrode         = %12.3e [m^{-2} s^{-1}]\n", N_i_abs_pow * WEIGHT / ELECTRODE_AREA / (no_of_cycles * PERIOD));
  1435.         fprintf(f,"Ion flux at grounded electrode        = %12.3e [m^{-2} s^{-1}]\n", N_i_abs_gnd * WEIGHT / ELECTRODE_AREA / (no_of_cycles * PERIOD));
  1436.         fprintf(f,"Mean ion energy at powered electrode  = %12.3e [eV]\n", mean_i_energy_pow);
  1437.         fprintf(f,"Mean ion energy at grounded electrode = %12.3e [eV]\n", mean_i_energy_gnd);
  1438.         fprintf(f,"Electron flux at powered electrode    = %12.3e [m^{-2} s^{-1}]\n", N_e_abs_pow * WEIGHT / ELECTRODE_AREA / (no_of_cycles * PERIOD));
  1439.         fprintf(f,"Electron flux at grounded electrode   = %12.3e [m^{-2} s^{-1}]\n", N_e_abs_gnd * WEIGHT / ELECTRODE_AREA / (no_of_cycles * PERIOD));
  1440.         fprintf(f,"--------------------------------------------------------------------------------\n");
  1441.        
  1442.         // calculate spatially and temporally averaged power absorption by the electrons and ions
  1443.        
  1444.         power_e = 0.0;
  1445.         power_i = 0.0;
  1446.         for (i=0; i<N_G; i++){
  1447.             for (j=0; j<N_XT; j++){
  1448.                 power_e += powere_xt[i][j];
  1449.                 power_i += poweri_xt[i][j];
  1450.             }
  1451.         }
  1452.         power_e /= (double)(N_XT * N_G);
  1453.         power_i /= (double)(N_XT * N_G);
  1454.         fprintf(f,"Absorbed power calculated as <j*E>:\n");
  1455.         fprintf(f,"Electron power density (average)      = %12.3e [W m^{-3}]\n", power_e);
  1456.         fprintf(f,"Ion power density (average)           = %12.3e [W m^{-3}]\n", power_i);
  1457.         fprintf(f,"Total power density(average)          = %12.3e [W m^{-3}]\n", power_e + power_i);
  1458.         fprintf(f,"--------------------------------------------------------------------------------\n");
  1459.         fclose(f);
  1460.     }
  1461. }
  1462.  
  1463. //------------------------------------------------------------------------------------------//
  1464. // main                                                                                     //
  1465. // command line arguments:                                                                  //
  1466. // [1]: number of cycles (0 for init)                                                       //
  1467. // [2]: "m" turns on data collection and saving                                             //
  1468. //------------------------------------------------------------------------------------------//
  1469.  
  1470. int main (int argc, char *argv[]){
  1471.     // printf(">> eduPIC: starting...\n");
  1472.     // printf(">> eduPIC: **************************************************************************\n");
  1473.     // printf(">> eduPIC: Copyright (C) 2021 Z. Donko et al.\n");
  1474.     // printf(">> eduPIC: This program comes with ABSOLUTELY NO WARRANTY\n");
  1475.     // printf(">> eduPIC: This is free software, you are welcome to use, modify and redistribute it\n");
  1476.     // printf(">> eduPIC: according to the GNU General Public License, https://www.gnu.org/licenses/\n");
  1477.     // printf(">> eduPIC: **************************************************************************\n");
  1478.  
  1479.     if (argc == 1) {
  1480.         printf(">> eduPIC: error = need starting_cycle argument\n");
  1481.         return 1;
  1482.     } else {
  1483.         strcpy(st0,argv[1]);
  1484.         arg1 = atol(st0);
  1485.         if (argc > 2) {
  1486.             if (strcmp (argv[2],"m") == 0){
  1487.                 measurement_mode = true;                  // measurements will be done
  1488.             } else {
  1489.                 measurement_mode = false;
  1490.             }
  1491.         }
  1492.     }
  1493.     if (measurement_mode) {
  1494.         printf(">> eduPIC: measurement mode: on\n");
  1495.     } else {
  1496.         printf(">> eduPIC: measurement mode: off\n");
  1497.     }
  1498.     set_electron_cross_sections_ar();
  1499.     set_ion_cross_sections_ar();
  1500.     calc_total_cross_sections();
  1501.  
  1502.     auto exc = init_excited_distr();
  1503.     printf("Excited state population - superparticles!!!\n");
  1504.     printf("%lf %lf\n", exc.first, exc.second);
  1505.  
  1506.     printf("Sanity check \n");
  1507.     fflush(stdout);
  1508.  
  1509.     // for (int i = 0; i < 10; ++i) {
  1510.     //     double E = i * DE_CS;
  1511.     //     printf("σ_super1(%.3f eV) = %e  σ_super2(%.3f eV) = %e\n",
  1512.     //         E, sigma[E_SUPER_1][i],
  1513.     //         E, sigma[E_SUPER_2][i]);
  1514.     // }
  1515.  
  1516.     std::ofstream file0("rates.dat"); file0 << std::scientific << std::setprecision(6);
  1517.     std::ofstream file1("excited_densities.dat"); file1 << std::scientific << std::setprecision(6);
  1518.  
  1519.     //test_cross_sections(); return 1;
  1520.     datafile = fopen("conv.dat","a");
  1521.     if (arg1 == 0) {
  1522.         if (FILE *file = fopen("picdata.bin", "r")) { fclose(file);
  1523.             printf(">> eduPIC: Warning: Data from previous calculation are detected.\n");
  1524.             printf("           To start a new simulation from the beginning, please delete all output files before running ./eduPIC 0\n");
  1525.             printf("           To continue the existing calculation, please specify the number of cycles to run, e.g. ./eduPIC 100\n");
  1526.             exit(0);
  1527.         }
  1528.         no_of_cycles = 1;
  1529.         cycle = 1;                                        // init cycle
  1530.         init(N_INIT);                                     // seed initial electrons & ions
  1531.         printf(">> eduPIC: running initializing cycle\n");
  1532.         Time = 0;
  1533.         do_one_cycle();
  1534.         print_excitation_densities();
  1535.         for (int i = 0; i < N_G; i++){
  1536.             double x = i*DX;
  1537.             file0 << avg_rate1f[i] << " " << avg_rate1b[i] << " " << avg_rate2f[i] << " " << avg_rate2b[i] << "\n";
  1538.             file1 << x << " " << e1_density[i] << " " << e2_density[i] << "\n";
  1539.         }
  1540.         cycles_done = 1;
  1541.     } else {
  1542.         no_of_cycles = arg1;                              // run number of cycles specified in command line
  1543.         load_particle_data();                            // read previous configuration from file
  1544.         printf(">> eduPIC: running %d cycle(s)\n",no_of_cycles);
  1545.         for (cycle=cycles_done+1;cycle<=cycles_done+no_of_cycles;cycle++) {
  1546.             do_one_cycle();
  1547.         }
  1548.         cycles_done += no_of_cycles;
  1549.     }
  1550.     fclose(datafile);
  1551.     save_particle_data();
  1552.     if (measurement_mode) {
  1553.         check_and_save_info();
  1554.     }
  1555.     printf(">> eduPIC: simulation of %d cycle(s) is completed.\n",no_of_cycles);
  1556.     file0.close();
  1557. }
  1558.  
Add Comment
Please, Sign In to add comment