Advertisement
phystota

Thermalization_2(structures)

Mar 24th, 2025
373
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.60 KB | None | 0 0
  1. #include <iostream>
  2. #include <random>
  3. #include <fstream>
  4.  
  5. #include <math.h>
  6. #include <time.h>
  7. #include <iomanip>  // For std::fixed and std::setprecision
  8.  
  9. #define n_e 100000
  10. #define V_0 30000.0     // max velocity using to generate random distribution ---- doesn't work -> produces skew distribution???
  11. #define Emin 0.0
  12. #define Emax 100.0
  13. #define bin_width 0.5
  14. #define m_e 9.1E-31 // electron mass in kg
  15. #define k_b 1.38E-23 // Boltzmann constant
  16. #define q 1.6E-19 // elementary charge    
  17. #define N ( (int)((Emax-Emin)/bin_width) ) // add 1 to include E_max if needed?
  18. #define P 0.005
  19. #define steps 200
  20.  
  21. struct Electron {
  22.  
  23.     //velocity components
  24.     double vx = 0.0;
  25.     double vy = 0.0;
  26.     double vz = 0.0;
  27.     //energy in eV
  28.     double energy = 0.0;
  29.     //Collision flag
  30.     bool collided = false;
  31.  
  32.     //initialization function // void func(Type0& t) → means the function expects a reference to variable t of type0
  33.     void initialize(std::mt19937& gen, std::uniform_real_distribution<double>& dis) {
  34.         // velocity angles in spherical coordinates
  35.         double phi = 2*M_PI*dis(gen);
  36.         double sinTheta = dis(gen);
  37.         double cosTheta = sqrt(1.0 - sinTheta*sinTheta);
  38.        
  39.         energy = Emax*dis(gen);
  40.        
  41.         double speed = sqrt(2*energy*k_b/m_e);
  42.  
  43.         vx = speed * sinTheta * cos(phi);
  44.         vy = speed * sinTheta * sin(phi);
  45.         vz = speed * cosTheta;
  46.  
  47.     }
  48.  
  49. };
  50.  
  51. int main() {
  52.  
  53.     std::vector<Electron> electrons(n_e); // better to use vector instead of simple array as it's dynamically allocated (beneficial for ionization)
  54.  
  55.     std::vector<int> histo_random(N, 0); // initialize N size zero-vector for random (initial) histogram
  56.     std::vector<int> histo_maxwell(N, 0); // initialize N size zero-vector for maxwellian histogram
  57.  
  58.     clock_t start = clock();
  59.  
  60.     std::random_device rd;
  61.     std::mt19937 gen(rd());
  62.     std::uniform_real_distribution<double> dis(0.0, 1.0);
  63.  
  64.     std::random_device rd1;
  65.     std::mt19937 gen1(rd1());
  66.     std::uniform_int_distribution<int> pair(0, n_e-1);
  67.  
  68.     std::ofstream file0("velocities.dat");    
  69.     if (!file0.is_open()) {
  70.         std::cerr << "Error opening file!" << std::endl;
  71.         return 1;
  72.     }
  73.  
  74.     std::ofstream file1("energies.dat");    
  75.     if (!file1.is_open()) {
  76.         std::cerr << "Error opening file!" << std::endl;
  77.         return 1;
  78.     }
  79.    
  80.     std::ofstream file2("energies_final.dat");    
  81.     if (!file2.is_open()) {
  82.         std::cerr << "Error opening file!" << std::endl;
  83.         return 1;
  84.     }
  85.  
  86.     std::ofstream file3("histo_random.dat");    
  87.     if (!file3.is_open()) {
  88.         std::cerr << "Error opening file!" << std::endl;
  89.         return 1;
  90.     }
  91.     file3 << std::fixed << std::setprecision(10);
  92.    
  93.     std::ofstream file4("histo_maxwell.dat");    
  94.     if (!file4.is_open()) {
  95.         std::cerr << "Error opening file!" << std::endl;
  96.         return 1;
  97.     }
  98.     file4 << std::fixed << std::setprecision(10);          
  99.  
  100.  
  101.     // Initialize all electrons
  102.     for (auto& e : electrons) {
  103.         e.initialize(gen, dis);
  104.     }
  105.  
  106.     for (int i = 0; i < n_e; i++){
  107.         file1 << i << " " << electrons.at(i).energy << "\n";
  108.         file0 << i << " " << electrons[i].vx << " " << electrons[i].vy << " " << electrons[i].vz << "\n";
  109.     }
  110.  
  111.     // for (int i = 0; i < N; i++){
  112.     //     std::cout << i << " " << histo_random.at(i) << "\n"; // using vector.at allows to access elements with boundary checkings
  113.     // }
  114.  
  115.  
  116.     for (int i = 0; i < n_e; i++){
  117.         int bin = (int)( (electrons[i].energy - Emin)/bin_width );
  118.         if (bin >=0 && bin < histo_random.size())
  119.             histo_random[bin]++;
  120.     }
  121.  
  122.     for (int i = 0; i < histo_random.size(); i++){\
  123.         double bin_start = Emin + i*bin_width;
  124. //        printf("%5.1f - %5.1f\t%d\n", bin_start, bin_start + bin_width, histo_random[i]);
  125.         file3 << i*bin_width << " " <<  static_cast<double>(histo_random[i])/electrons.size() << "\n"; // dividing by n_e to get normalized distribution
  126.     }
  127.  
  128.  
  129.     for (int t = 0; t < steps; t++){
  130.  
  131.         std::ostringstream filename;
  132.         filename << "data/distribution_" << std::setw(4) << std::setfill('0') << t << ".dat";
  133.  
  134.         std::ofstream file(filename.str());
  135.         if (!file.is_open()){
  136.         std::cerr << "Error opening file: " << filename.str() << std::endl;
  137.         return 1;
  138.         }
  139.  
  140.         // setting flags to false each timestep
  141.         for (int j = 0; j < n_e; j++){
  142.             electrons.at(j).collided = false;
  143.         }
  144.  
  145.         for (int i = 0 ; i < n_e; i++){
  146.             if (dis(gen) < P) {
  147.                 int partner = -1;
  148.                 int attempts = 0;
  149.  
  150.                 while (attempts < n_e){
  151.                     int candidate = pair(gen1);
  152.                     if (candidate != i && !electrons.at(candidate).collided){
  153.                         partner = candidate;
  154.                         break;
  155.                     }
  156.                     attempts++;
  157.                 }
  158.  
  159.                 if (partner != -1) {
  160.                     electrons.at(i).collided = true;
  161.                     electrons.at(partner).collided = true;
  162.                 }
  163.  
  164.                 // ----   Collision energy redistribution module
  165.  
  166.                 // first particle X Y Z initial velocities
  167.                 double V0_x_1 = electrons[i].vx;
  168.                 double V0_y_1 = electrons[i].vy;
  169.                 double V0_z_1 = electrons[i].vz;
  170.  
  171.                 // second particle X Y Z initial velocities
  172.                 double V0_x_2 = electrons[partner].vx;
  173.                 double V0_y_2 = electrons[partner].vy;
  174.                 double V0_z_2 = electrons[partner].vz;
  175.  
  176.                 // initial relative velocity X Y Z (must be equal to final relative velocity in center-of-mass frame)
  177.  
  178.                 double V0_rel_x = (V0_x_1 - V0_x_2)/2.0;
  179.                 double V0_rel_y = (V0_y_1 - V0_y_2)/2.0;
  180.                 double V0_rel_z = (V0_z_1 - V0_z_2)/2.0;
  181.  
  182.                 double V0_rel = sqrt(V0_rel_x*V0_rel_x + V0_rel_y*V0_rel_y + V0_rel_z*V0_rel_z);
  183.  
  184.                 // center-of-mass frame initial velocity (magnitude of it must be equal to the counterpart in this frame)
  185.  
  186.                 double V_cm_x = (V0_x_1 + V0_x_2)/2.0;
  187.                 double V_cm_y = (V0_y_1 + V0_y_2)/2.0;
  188.                 double V_cm_z = (V0_z_1 + V0_z_2)/2.0;
  189.  
  190.                 double V_cm = sqrt(V_cm_x*V_cm_x + V_cm_y*V_cm_y + V_cm_z*V_cm_z);
  191.  
  192.                 // generating random variables to calculate random direction of center-of-mass after the collision
  193.  
  194.                 double R1 = dis(gen);
  195.                 double R2 = dis(gen);
  196.  
  197.                 // calculating spherical angles for center-of-mass random direction
  198.                 double theta = acos(1.0- 2.0*R1);
  199.                 double phi = 2*M_PI*R2;
  200.  
  201.                 //calculating final relative velocity with random direction
  202.  
  203.                 double V_rel_x = V0_rel*sin(theta)*cos(phi);
  204.                 double V_rel_y = V0_rel*sin(theta)*sin(phi);
  205.                 double V_rel_z = V0_rel*cos(theta);
  206.  
  207.                 double V_rel = sqrt(V_rel_x*V_rel_x + V_rel_y*V_rel_y + V_rel_z*V_rel_z);
  208.  
  209.                 //calculating final velocity of first particle
  210.  
  211.                 double V_x_1 = V_cm_x + V_rel_x/2.0;
  212.                 double V_y_1 = V_cm_y + V_rel_y/2.0;
  213.                 double V_z_1 = V_cm_z + V_rel_z/2.0;
  214.  
  215.                 double V_1 = sqrt(V_x_1*V_x_1 + V_y_1*V_y_1 + V_z_1*V_z_1);
  216.  
  217.                 //calculating final velocity of second particle
  218.  
  219.                 double V_x_2 = V_cm_x - V_rel_x/2.0;
  220.                 double V_y_2 = V_cm_y - V_rel_y/2.0;
  221.                 double V_z_2 = V_cm_z - V_rel_z/2.0;
  222.  
  223.                 double V_2 = sqrt(V_x_2*V_x_2 + V_y_2*V_y_2 + V_z_2*V_z_2);\
  224.  
  225.                 // calculating final energies of first and second colliding particles
  226.  
  227.                 electrons[i].energy = V_1*V_1*m_e/(2.0*k_b);
  228.                 electrons[partner].energy = V_2*V_2*m_e/(2.0*k_b);          
  229.  
  230.                 // --- collision energy redistrubution module ends    
  231.  
  232.             }
  233.         }
  234.  
  235.         for (int i = 0; i < n_e; i++){
  236. //        filename << i << " " << electron_e[i] << "\n";
  237.         int bin = (int)( (electrons[i].energy - Emin)/bin_width );
  238.         if (bin >=0 && bin < N)
  239.             histo_maxwell[bin]++;
  240.         }
  241.  
  242.         for (int i = 0; i < N; i++){
  243.             double bin_start = Emin + i*bin_width;
  244.             file << i*bin_width << " " <<  static_cast<double>(histo_maxwell[i])/electrons.size() << "\n"; // later need to divide by total partcles number to get normalized distribution
  245.             histo_maxwell[i] = 0;
  246.         }
  247.  
  248.         file.close();
  249.  
  250.     }
  251.     for (int i = 0; i < n_e; i++){
  252.  
  253.         file2 << i << " " << electrons[i].energy << "\n";
  254.  
  255.         int bin = (int)( (electrons[i].energy - Emin)/bin_width );
  256.         if (bin >=0 && bin < histo_maxwell.size())
  257.             histo_maxwell[bin]++;
  258.     }
  259.  
  260.     for (int i = 0; i < histo_maxwell.size(); i++){
  261.         double bin_start = Emin + i*bin_width;
  262. //        printf("%5.1f - %5.1f\t%d\n", bin_start, bin_start + bin_width, histo_maxwell[i]);
  263.         file4 << i*bin_width << " " <<  static_cast<double>(histo_maxwell[i])/electrons.size() << "\n"; // dividing by partcles number to get normalized distribution
  264.     }
  265.  
  266.  
  267.     file0.close();
  268.     file1.close();
  269.     file2.close();
  270.     file3.close();
  271.     file4.close();
  272.  
  273.     clock_t end = clock();
  274.  
  275.     double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
  276.  
  277.     std::cout << "Energies written successfuly\n";
  278.     std::cout << "Elapsed time: %f seconds " << elapsed << "\n";
  279.  
  280.  
  281.     return 0;
  282.  
  283.  
  284. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement