Question about “SetMaxElectronEnergy()"

I‘m using AvalancheMicroscopic to simulate the current signal output of a DriftTube.
I found that the output signal varies when setting different energy limits.
SetMaxElectronEnergy(800)


SetMaxElectronEnergy(600)

SetMaxElectronEnergy(1000)

Although the signal output does not appear significantly different under the limitation of an electron energy of 600eV, the maximum amplitude exceeds -0.3 at 1000eV.
In addition, I conducted 6 repeated simulations with the same parameters at a setting of SetMaxElectronEnergy(800), and the amplitude of the output signal remained around -0.25, never exceeding -0.3.
I see in the user guide that SetMaxElectronEnergy limits the range of the cross-section table.
But I’m not quite sure what limits to set if I want to simulate more realistic signal output results.

I think @hschindl can help you.

Hi,
you many avalanches did you simulate for each setting? The avalanche size can have significant event-by-event fluctuations. In theory, the max. electron energy you set should not have a significant impact on the results. If an energy exceeding the maximum occurs during an avalanche, the collision-rate table is automatically recomputed with an increased upper limit.
By the way, 600 eV is already a quite high value for an avalanche. Are you sure that the electrons reach such a high value in your simulation?

Hi!
Thanks for your reply. I recalculated the positions within each cluster on the initial path formed by TrackSrim.Afterwards, I performed AvalancheElectronon of every electron in the clusters. This is the code I used to simulate the avalanche:

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, projectileT, projectiledx, projectiledy, projectiledz);    
    if (notnewtrack) {
      std::cerr << "Generating clusters failed; skipping this particle's track.\n";
      continue;
    }
    unsigned int netot = 0;
    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) {
        std::cout  << informationofclusters.size() <<  " clusters infornation done.\n";
        break; 
      }
    }
 
    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));  //Calculate the distance between two clusters
      double duation=distanceofclusters/speedofprojectile;                  //Calculate the transport time of incident ions between two clusters
      informationofclusters[i+1][3]=informationofclusters[i][3]+duation;     //Adjust the generation time of the i+1th cluster by adding transport time to the i-th cluster time
    }
    
    omp_set_num_threads(60);   
    #pragma omp parallel for
      //for(int j=60; j<61; ++j){  
      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";     
          avalancheelectrons=avalancheelectrons+avalanchee;
          avalancheions=avalancheions+avalanchei;                     
          std::cout <<  "AvalancheElectron end\n";
          std::cout << k+1<< "/" << informationofclusters[j][4] <<  " Transport of electron in "\
                    << j+1<< "/" << informationofclusters.size() << " cluster is done.\n";  
        }
        avalancheelectrons=avalancheelectrons/informationofclusters[j][4];
        avalancheions=avalancheions/informationofclusters[j][4];                 
        printavalancheinclusters(j,informationofclusters[j][0],informationofclusters[j][1],informationofclusters[j][2],\
                                 informationofclusters[j][3],informationofclusters[j][6],avalancheelectrons,avalancheions,name);
        
        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]);    
      }
    
  }

After reading the UserGuide, I also believe that the setting of this value should not have such a huge impact on the results.

Are you sure that the electrons reach such a high value in your simulation?

I’m not sure about that. I just want to set a sufficiently large value. My working voltage is 1100V, anode wire diameter is 30μm, Drifttube diameter 3.5cm.
According to the UserGuide, for electron avalanches, a range of 40-200eV is generally sufficient. However, when I set it to 80eV, the output signal is as follows
SetMaxElectronEnergy(80)


This looks like only a portion of the electrons have undergone avalanche calculations.

1 Like

Usually TrackSrim and AvalancheMicroscopic are not an ideal combination. You typically use TrackSrim if you have a highly-ionising charged particle that creates lots of electron/ion pairs along the track. Using AvalancheMicroscopic to simulate every electron avalanche individually will take a lot of time; and it’s also typically an overkill. For a drift tube, the advantage of AvalalancheMicroscopic compared to DriftLineRKF is that it simulates fluctuations in the avalanche size; but these will anyway be washed out if you have many primary electrons. Long story short, I would recommend considering using DriftLineRKF for your application.

Having said that, the max. electron energy you set should not (significantly) affect the average gain and signal. If the initial value is too low, it will automatically be updated (increased).
Are the plots you showed for a single avalanche? Or do they correspond to the average over many avalanches (and if yes how many)?

Thank you again for your reply. My incident particles is Li , and the gas medium is Ar85%, CO215%, Therefore, I used TrackSrim to simulate the incident track of Li. The signal output above is caused by the incident of one Li particle.

Application app("app", &argc, argv);
  float name[4];
  double ratioofAr=0.85;          
  double ratioofCO2=1-ratioofAr;
  name[0]=ratioofAr*100;
  name[1]=ratioofCO2*100;
  MediumMagboltz gas;
  const double pressure = 0.26;   
  name[2]=pressure;
  const double temperature = 300;                   
  gas.SetComposition("Ar", ratioofAr*100, "CO2", ratioofCO2*100);        
  gas.SetTemperature(temperature);                   
  gas.SetPressure(pressure*AtmosphericPressure);                        

  gas.EnableAutoEnergyLimit(false);
   gas.SetMaxElectronEnergy(800);
  gas.EnableCrossSectionOutput();   
  gas.Initialise(true);  
  const std::string path = std::getenv("GARFIELD_HOME");
  gas.LoadIonMobility(path + "/Data/IonMobility_Ar+_Ar.txt");  

  ComponentAnalyticField cmp;
  cmp.SetMedium(&gas);
  const double rWire = 30.e-4;   
  const double rTube = 3.5;     

  const double vWire = 1100;     
  name[3]=vWire;
  const double vTube = 0.;        
  // Add the wire in the centre.
  cmp.AddWire(0, 0, 2 * rWire, vWire, "s");
  // Add the tube.
  cmp.AddTube(rTube, vTube, 0, "t");
  cmp.AddReadout("s");        
  // ---make a sensor.
  Sensor sensor;
  sensor.AddComponent(&cmp);     
  sensor.AddElectrode(&cmp, "s");     
  // Set the signal time window.
  const double tstep = 0.1;    
  const double tmin = 0;     
  const double tmax=20000;         //**********      
  const unsigned int nbins = (tmax-tmin)/tstep;  
  sensor.SetTimeWindow(tmin, tstep, nbins);
  sensor.SetTransferFunction(Transferfunction);
  sensor.ClearSignal();


  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);     // alpha 1.47e6 eV   Li+  0.84e6 eV
  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.SetTargetClusterSize(100);     
  //int numbersofcluster=100;           
  //tr.SetClustersMaximum(2*numbersofcluster);    
  tr.EnableTransverseStraggling(false);
  tr.EnableLongitudinalStraggling(false);

For a drift tube, the advantage of AvalalancheMicroscopic compared to DriftLineRKF is that it simulates fluctuations in the avalanche size; but these will anyway be washed out if you have many primary electrons. Long story short, I would recommend considering using DriftLineRKF for your application.

What I want to observe is the waveform characteristics of the output signal caused by a particle incident. But DriftLineRKF will lose many details of the electron avalanche process, making the output signal very sharp. Or perhaps there were some issues with my settings when using DriftLineRKF, which caused the signal I output to appear different from the real situation (in comparison, the signal obtained using AvalancheMicroscopic is very close to the real situation).

This is the result I simulated using DriftLineRKF:



The code is as follows:

int main(int argc, char * argv[]) {

	TApplication app("app", &argc, argv);
	MediumMagboltz gas;
	//gas.SetComposition("ar", 85., "co2", 15.);
	//gas.SetPressure(0.26 * AtmosphericPressure );
	//gas.SetTemperature(300);
  //gas.EnableAutoEnergyLimit(false);
  gas.SetMaxElectronEnergy(200);
	
	gas.LoadGasFile("ar_85_co2_15.gas");
	const std::string path = std::getenv("GARFIELD_HOME");
	gas.LoadIonMobility(path + "/Data/IonMobility_Ar+_Ar.txt");


	ComponentAnalyticField cmp;
	cmp.SetMedium(&gas);
	
	//
	const double rWire = 30.e-4;//cm
	const double rTube = 3.5;//cm
	//
	const double vWire = 1100.;
	const double vTube = 0.;
	//
	cmp.AddWire(0 , 0, 2* rWire, vWire, "s");
	cmp.AddTube(rTube, vTube, 0 , "t");
	cmp.AddReadout("s");

	//
	Sensor sensor;
	sensor.AddComponent(&cmp);
	sensor.AddElectrode(&cmp, "s");
 /*
  const double tstep = 0.5;
  const double tmin = -0.5 * tstep;
  const unsigned int nbins = 1000;
  sensor.SetTimeWindow(tmin, tstep, nbins);
  */
  
	// Set the signal time window.
 
  const double tstep = 0.1;     
  const double tmin = 0;     
  const double tmax=20000;             
  const unsigned int nbins = (tmax-tmin)/tstep;   
  sensor.SetTimeWindow(tmin, tstep, nbins);
  //sensor.SetTransferFunction(Transferfunction);
  sensor.ClearSignal();
 


	
	//----alpha in -----
	// Read the SRIM output file. 
	TrackSrim track(&sensor);
 	const std::string file = "Li_in_Ar_CO2_gas.txt";
 	if (!track.ReadFile(file)) {
 	std::cerr << "Reading Li_in_Ar_CO2_gas.txt file failed.\n";
 	return 1;
 	}
  	
	// Set the initial kinetic energy of the particle (in eV).
 	 track.SetKineticEnergy(0.84e6);
   track.SetWorkFunction(27.7);      
   track.SetFanoFactor(0.172);      
   const double za = 0.85 * (18. / 39.948) +0.15 * (22. / 44.0095);  // Set A and Z of the gas     (not sure what's the correct mixing law).
   track.SetAtomicMassNumbers(22. / za, 22);
  	// Specify how many electrons we want to be grouped to a cluster.
   //track.SetTargetClusterSize(100);
   track.EnableTransverseStraggling(false);
   track.EnableLongitudinalStraggling(false);
  
  DriftLineRKF drift(&sensor);
  drift.SetGainFluctuationsPolya(0., -1);
  drift.EnableIonTail();
  drift.EnableSignalCalculation();
  
  
  
  
	
  
  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;  
    int nc = 0, ne = 0, nce;
    double eDepSum = 0;
    double xc, yc, zc, tc, eDepc, extra;
    
  track.NewTrack(projectilex, projectiley, projectilez, projectileT, projectiledx, projectiledy, projectiledz);

  while (track.GetCluster(xc, yc, zc, tc, nce, eDepc, extra)) {

    drift.SetIonSignalScalingFactor(nce);
    drift.DriftIon(xc, yc, zc, tc);
    drift.SetElectronSignalScalingFactor(nce);
    drift.DriftElectron(xc, yc, zc, tc);
}


  
  ViewSignal signalView;
  signalView.SetSensor(&sensor);
  signalView.PlotSignal("s");
  
  app.Run();
  return 0;
}

Here are the gasfile and SRIM file.
rkf.zip (13.6 KB)

Hi,
apologies for the late reply. The warning message “Integrating the Townsend coefficients would leak to exponential overflow.” points to an issue with your configuration: for the given geometry and gas mixture, you would get an unrealistically high gain.

Thanks the reply!

For the given geometry and gas mixture, you would get an unrealistically high gain.

How to avoid this overflow? My gasfile table should have included the electric field strength caused by geometry and the working voltage.
And, if the gain is greater than the actual situation, should the peak value of the signal be higher than that of AvalalancheMicroscopic? But the peak value has decreased.

Can you double-check that the voltage settings you are using are realistic for the geometry, pressure and gas mixture you are using? The overflow suggests that you have a very high Townsend coefficient; which would also be consistent with the high electron energies you saw when using microscopic tracking.

Can you double-check that the voltage settings you are using are realistic for the geometry, pressure and gas mixture you are using?

The equipment I simulated is a boron coated proportional counter tube. The normal geometric design of this detector is a 3.5cm shell radius and a 30 μ m anode wire radius. The recommended operating voltage is generally between 1100V-1300V. In order to achieve counting, there should indeed be a large electron avalanche during operation to obtain a higher signal peak.

In addition, if I want the simulation results of DriftLineRKF to obtain more detailed signals similar to AvalalancheMicroscopic, can I achieve this by SetTargetClusterSize(), like SetTargetClusterSize(10).

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