Li+ in a cylindrical DriftTube

I want to simulate the current signal output by Li+incident on a cylindrical drift tube.
Using the SRIM program, I generated an energy loss file for Li in an environment of 80% Ar and 20% CO2. I modified the example in GasFile and generated a gas fire with 80% Ar and 20% CO2.
Afterward, I planned to use DriftLineRKF to calculate the drift of electrons, but I followed the example in DriftTube and found that the DriftLineRKF class does not have a getElectron function.
Also, I have another question. If I have GasFile, can I only use DriftLineRKF to drift electrons? If I use AvlancheMC method, does it not use GasFile?

Dear @Migu

Why would you need a getElectron() function? What would you like to do? You have GetEndPoint() to get the coordinates of the end of the driftline and GetGain() and GetLoss() to get the gain and the electrons attached. You even have GetAvalancheSize() to get the number of electrons and ions in the avalanche.

Also AvalancheMC requires the use of a GasFile.
greets
Piet

Dear @Piet
Thank you for your reply!
I am trying to simulate the current signal generated by Li+incidence. Currently, I have used Avalanche Microscopic to drift electrons and AvlancheMC to drift ions generated during initial ionization and avalanche. The entire simulation process is very slow, and it still takes 3 hours to complete the calculation with 60 cores in parallel (processing electron drift calculations).This process did not use gas files, but only set the composition, temperature, and pressure of the gas
My first question is, can using the generated GasFile accelerate the process of electron drift calculation (similar to giving a Monte Carlo grid)?
The second question is, why is there a significant difference between the current signal generated by DriftLinRKF and the signal generated by my previous micro tracking? The former has a very short pulse width and always has a larger amplitude than the latter (under the same gas conditions).
Best regards
Migu

AvalancheMicroscopic and DriftLineRKF should give statistically compatible results. Can you post the lines of code you used for simulating the electrons? When simulating electrons from a “SRIM cluster” using DriftLineRKF, you would normally simulate the drift from a given cluster only once and scale the signal according to the number of electrons in the cluster (see Examples/Srim/trimsignal.C · master · garfield / garfieldpp · GitLab). With AvalancheMicroscopic on the other hand, you’ll need to simulate individual drift lines/avalanches for each of the electrons in the cluster.

Microscopic simulation of the electrons is likely to be an overkill in your case. Using DriftLineRKF is probably a better (and much faster) option.

Dear @hschindl
Here is my code:

TrackSrim tr;
tr.SetSensor(&sensor); 
const std::string file = "Li_Ar_85_CO2_15_300K_0.26Atm.txt";   
if (!tr.ReadFile(file)) {
  std::cerr << "Reading SRIM file failed.\n";
 }

tr.SetKineticEnergy(0.84e6);    
tr.SetWorkFunction(27.7);     
tr.SetFanoFactor(0.172);      
 const double za = ratioofAr * (18. / 39.948) +ratioofCO2 * (22. / 44.0095);  // Set A and Z of the 
gas (not sure what's the correct mixing law).
tr.SetAtomicMassNumbers(22. / za, 22);

tr.EnableTransverseStraggling(false);
tr.EnableLongitudinalStraggling(false);

const double rTrack =3.0;     //**********
const double projectilex= rTrack;
const double projectiley= sqrt(rTube * rTube - rTrack * rTrack);
const double projectilez= 0.;  //**********

const double projectiledx=0.;    //**********
const double projectiledy=-1.; //**********
const double projectiledz=0.; //**********

const double projectileT=0.;   //**********
const unsigned int nTracks = 1;    //**********    

for (unsigned int n = 0; n < nTracks; ++n) {
const bool notnewtrack= !tr.NewTrack(projectilex, projectiley, projectilez, projectile, 
projectiledx, projectiledy, projectiledz);    
if (notnewtrack) {
  std::cerr << "Generating clusters failed; skipping this particle's track.\n";
  continue;
}

unsigned int netot = 0;
std::vector<std::array<double,7>> informationofclusters;
while (true) {                          
  int ne = 0;
  double xc, yc, zc, tc, ec, ekin;
  const bool done = tr.GetCluster(xc, yc, zc, tc, ne, ec, ekin);  //
  if(done) {                                                                
  informationofclusters.push_back({xc, yc, zc, tc, ne, ec,ekin});          
  netot += ne;       
  }   
  if (!done) {
    hX->Fill(xc);  
    hY->Fill(yc);   
    hZ->Fill(zc);  
    hNe->Fill(netot);   
    std::cout  << informationofclusters.size() <<  " clusters infornation is passed to file.\n\n";
    break;                 
  }
}

//Correct the timing of cluster generation
double MLi=6.9405*1.66053886e-27;     //**********  
double Mev=1.602176565e-13;              
for(int i=0;i<informationofclusters.size()-1;++i){
  double speedofprojectile=sqrt(2*informationofclusters[i+1][6]*Mev/MLi)/1.e7;    
  double distanceofclusters=sqrt(pow(informationofclusters[i+1][0]-informationofclusters[i][0],2) \
                                +pow(informationofclusters[i+1][1]-informationofclusters[i][1],2) \
                                +pow(informationofclusters[i+1][2]-informationofclusters[i][2],2));  
  double duation=distanceofclusters/speedofprojectile;                  
  informationofclusters[i+1][3]=informationofclusters[i][3]+duation;    
}


omp_set_num_threads(60);    
#pragma omp parallel for
  for(int j=0; j<informationofclusters.size(  ); ++j){  // informationofclusters.size()
    double avalancheelectrons=0;
    double avalancheions=0;   
    AvalancheMicroscopic driftelectron;
    driftelectron.SetSensor(&sensor);
    driftelectron.EnableSignalCalculation();      
    driftelectron.EnablePlotting(&driftView);  
    
    AvalancheMC driftion;           
    driftion.SetSensor(&sensor);     
    driftion.SetDistanceSteps(2.e-4);      
    driftion.EnableSignalCalculation();    
    AvalancheMC driftprimaryion;           
    driftprimaryion.SetSensor(&sensor);     
    driftprimaryion.SetDistanceSteps(2.e-4);        
    driftprimaryion.EnableSignalCalculation();    

    for (int k = 0; k <informationofclusters[j][4]; ++k) {            
      std::cout << k+1<< "/" << informationofclusters[j][4] <<  " Transport of electron in " \
                << j+1<< "/" << informationofclusters.size() << " cluster begin:\n"; 
      std::cout <<  "AvalancheElectron begin;                     "; 
      //#pragma omp critical
      {
      driftelectron.AvalancheElectron(informationofclusters[j][0], informationofclusters[j][1], \
                                      informationofclusters[j][2], informationofclusters[j][3], 0.00001, 0., 0., 0.);  
      }
      int avalanchee,avalanchei;      
      driftelectron.GetAvalancheSize(avalanchee,avalanchei);   
      std::cout << "numberofavalancheelectron is " <<avalanchee <<"        " << "numberofavalancheion is " <<avalanchei <<"\n";     

      std::cout <<  "AvalancheElectron end\n";
      std::cout << k+1<< "/" << informationofclusters[j][4] <<  " Transport of electron in "\
                << j+1<< "/" << informationofclusters.size() << " cluster is done.\n";  
    }

  
    std::cout <<  "Ion tranport in Avalanche begin;             ";
    int np=0;
    np=driftelectron.GetNumberOfElectronEndpoints();  
    std::cout <<  "number of Ions in last electron drift line    "<< np <<"\n";
    for(int m=0; m<np; ++m){                         
      double xestart, yestart, zestart, testart, eestart;
      double xeend, yeend, zeend, teend, eeend;
      int status;

      driftelectron.GetElectronEndpoint(m, xestart, yestart, zestart, testart, eestart, xeend, yeend, zeend, teend, eeend, status);
      //#pragma omp critical
      {
      driftion.SetIonSignalScalingFactor(informationofclusters[j][4]);
      driftion.DriftIon(xestart, yestart, zestart, testart);
      }
    } 
    std::cout <<  "Ion tranport in Avalanche end\n";

    //#pragma omp critical
    {
    driftprimaryion.SetIonSignalScalingFactor(informationofclusters[j][4]);
    driftprimaryion.DriftIon(informationofclusters[j][0], informationofclusters[j][1], \
                             informationofclusters[j][2], informationofclusters[j][3]);       
    }

  }

}

AvalancheMC and DriftLineRKF are faster methods to calculate electron driftlines than AvalancheMicroscopic, but they require both to load a previously generated GasFile. Those first two methods use swarmparameters they read from the gasfile, while the latter method simulates each individual electron-atom collision. So using a GasFile allows you to use faster computation methods.

Short pulse width and larger amplitude is a hint that you are only looking at the electron signal, while ion signals are typically more important in wire based gaseous detectors. As you are using 2 different methods for simulating electron driftlines and ion driftlines, make sure that both methods feed into your object of the viewSignal class.

kind regards
Piet

Thank you so much for your reply. Indeed, the current version of my program primarily accounts for the drift of electrons, while the impact of ions may lead to an extended tail in the signal output. Nevertheless, I am puzzled by the significant discrepancy in the maximum amplitude of the signal. Whether I employ the DriftLineRKF method or engage in microscopic tracking of individual electrons, the difference in amplitude should not be as pronounced as the current 9-fold variation observed(DriftLineRKF producing a signal that is nine times greater). It seems likely that there is an issue within my program that necessitates further investigation

Best regards
Migu

How did you simulate the electrons using DriftLineRKF? Did you specify a fixed gain or is it calculated from the table of Townsend coefficients given in the gas file?

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.